File tree Expand file tree Collapse file tree 6 files changed +92
-1
lines changed Expand file tree Collapse file tree 6 files changed +92
-1
lines changed Original file line number Diff line number Diff line change 821
821
[x]
822
822
(instance? basilisp.lang.delay/Delay x))
823
823
824
+ (defn force
825
+ "If x is a Delay, returned the possibly cached value of x. Otherwise, return
826
+ x."
827
+ [x]
828
+ (if (delay? x)
829
+ @x
830
+ x))
831
+
832
+ (defn promise
833
+ "Return a promise object which can be set exactly once using `deliver`.
834
+ Readers may block waiting for the value of the promise using `@` or `deref`.
835
+ If the value has already been realized, then reading the value of the
836
+ promise will not block. Readers may check if the promise has been delivered
837
+ using `realized?`."
838
+ []
839
+ (basilisp.lang.promise/Promise))
840
+
841
+ (defn deliver
842
+ "Deliver the value v to the promise p. If p already has a value, then a
843
+ subsequent call to `deliver` for p will have no effect."
844
+ [p v]
845
+ (.deliver p v))
846
+
824
847
;;;;;;;;;;;;;;;;;;;;;;;;;;
825
848
;; Arithmetic Functions ;;
826
849
;;;;;;;;;;;;;;;;;;;;;;;;;;
Original file line number Diff line number Diff line change @@ -434,6 +434,7 @@ def _is_redefable(v: Var) -> bool:
434
434
_LIST_ALIAS = genname ("llist" )
435
435
_MAP_ALIAS = genname ("lmap" )
436
436
_MULTIFN_ALIAS = genname ("multifn" )
437
+ _PROMISE_ALIAS = genname ("promise" )
437
438
_READER_ALIAS = genname ("reader" )
438
439
_RUNTIME_ALIAS = genname ("runtime" )
439
440
_SEQ_ALIAS = genname ("seq" )
@@ -454,6 +455,7 @@ def _is_redefable(v: Var) -> bool:
454
455
"basilisp.lang.list" : _LIST_ALIAS ,
455
456
"basilisp.lang.map" : _MAP_ALIAS ,
456
457
"basilisp.lang.multifn" : _MULTIFN_ALIAS ,
458
+ "basilisp.lang.promise" : _PROMISE_ALIAS ,
457
459
"basilisp.lang.reader" : _READER_ALIAS ,
458
460
"basilisp.lang.runtime" : _RUNTIME_ALIAS ,
459
461
"basilisp.lang.seq" : _SEQ_ALIAS ,
Original file line number Diff line number Diff line change @@ -37,7 +37,7 @@ def __deref(state: _DelayState) -> _DelayState:
37
37
return _DelayState (f = state .f , value = state .f (), computed = True )
38
38
39
39
def deref (self ) -> Optional [T ]:
40
- return self ._state .swap (Delay .__deref ).value
40
+ return self ._state .swap (self .__deref ).value
41
41
42
42
@property
43
43
def is_realized (self ) -> bool :
Original file line number Diff line number Diff line change
1
+ import threading
2
+ from typing import Optional , TypeVar
3
+
4
+ from basilisp .lang .interfaces import IBlockingDeref
5
+
6
+ T = TypeVar ("T" )
7
+
8
+
9
+ # pylint: disable=assigning-non-slot
10
+ class Promise (IBlockingDeref [T ]):
11
+ __slots__ = ("_condition" , "_is_delivered" , "_value" )
12
+
13
+ def __init__ (self ) -> None :
14
+ self ._condition = threading .Condition ()
15
+ self ._is_delivered = False
16
+ self ._value : Optional [T ] = None
17
+
18
+ def deliver (self , value : T ):
19
+ with self ._condition :
20
+ if not self ._is_delivered :
21
+ self ._is_delivered = True
22
+ self ._value = value
23
+
24
+ def deref (
25
+ self , timeout : Optional [float ] = None , timeout_val : Optional [T ] = None
26
+ ) -> Optional [T ]:
27
+ with self ._condition :
28
+ if self ._condition .wait_for (lambda : self ._is_delivered , timeout = timeout ):
29
+ return self ._value
30
+ else :
31
+ return timeout_val
32
+
33
+ @property
34
+ def is_realized (self ) -> bool :
35
+ with self ._condition :
36
+ return self ._is_delivered
Original file line number Diff line number Diff line change @@ -390,6 +390,7 @@ class Namespace:
390
390
"basilisp.lang.list" ,
391
391
"basilisp.lang.map" ,
392
392
"basilisp.lang.multifn" ,
393
+ "basilisp.lang.promise" ,
393
394
"basilisp.lang.reader" ,
394
395
"basilisp.lang.runtime" ,
395
396
"basilisp.lang.seq" ,
Original file line number Diff line number Diff line change
1
+ import threading
2
+
3
+ import basilisp .lang .vector as vec
4
+ from basilisp .lang .promise import Promise
5
+
6
+
7
+ def test_promise ():
8
+ v = vec .v (1 , 2 , 3 )
9
+
10
+ p = Promise ()
11
+ assert False is p .is_realized
12
+
13
+ def set_promise ():
14
+ p .deliver (v )
15
+
16
+ assert "not set yet" == p .deref (timeout = 0.2 , timeout_val = "not set yet" )
17
+ assert False is p .is_realized
18
+
19
+ t = threading .Thread (target = set_promise )
20
+ t .start ()
21
+ t .join ()
22
+
23
+ assert v == p .deref ()
24
+ assert True is p .is_realized
25
+
26
+ p .deliver ("another value" )
27
+
28
+ assert v == p .deref ()
29
+ assert True is p .is_realized
You can’t perform that action at this time.
0 commit comments