Closed AndreVanDelft closed 8 years ago
For the implementation: I think a ~~> s
may be shorthand for _msgFrom:a ~~> s
and likewise for all variations of the LHS and the arrow. This is what the compiler should do.
Maybe it would be good to allow for ~/~>
as well; the internals of _msgFrom
(possibly through some kind of initialization) could decide on what incoming messages to fail with exceptions.
Essentially it should work the same as the current implementation. Since multiple instances of _msgFrom
may be active concurrently, they need to know which of them should handle a given message. That depends on the specified receiver, and also on the acceptable data flows in the specified arrows. So the code inside the _msgFrom
script would need access to that information. That is certainly possible with a high level method available from the script
node, which looks up the dataflow construct one level higher.
We drop the special support of a local sender
value. Thus, this proposal is not married to Akka actors any more; it may be applicable to different frameworks as well - I don't know yet.
Good idea. I think here the theory should become wider than the actors and the actors should become the special case of the theory. For actors are not the only case where two entities exchange data.
If we make an implicit conversion ActorRef => Script
the right way, a ~~> s
syntax will become available by default.
Maybe we should also generalize the ?a
syntax, where the source is unknown till the transmission takes place. It could then be used in constructs like a ~~> b
, b = ?source ~~(data)~~ [handler]
, that is ~~>
automatically transmitting the data inside the RHS script, if it is a script call on the RHS.
A ready use case for the latter: the SubScriptApplication convenience class has the method live
which is an entry point, but the Java/Scala entry point is a main(args: Array[String])
- it accepts input. In some SubScript programs, I’d also like to accept some input. For this, we’d need to redefine the live
as live(args: Array[String])
but it will break the API and cause the need to rewrite the examples to use the live(args: Array[String])
version.
If ?a
syntax is implemented, however, we’d be able just to feed the args from the main to the abstract live
with ^args ~~> live
. Then, if the user wants actually to accept some arguments, they will write live = ?source ~~(args: Array[String])~~> theirCode
. The listener ?source
will wait for the args, then proceed. If the user doesn’t want to accept any input, they will just write live = theirCode
as usual, without handling any data.
In general, I think scripts shouldn’t be like methods in that they accept their arguments only at the invocation time. They would look much better if they could accept anything at any point of their lifecycle.
On Apr 23, 2016, at 21:03, André van Delft notifications@github.com wrote:
The current syntax for actor message reception, <<...>>, has three down sides:
it is a bracket pair with potentially large contents. I have put much energy in SubScript fighting the need for such bracket pairs, because looking up a related bracket far away hinders code understanding it is in principle nice that such message reception may be nested using the brackets, but the sender is only available for the innermost message. there is semantic overlap with the current dataflow syntax, but syntax is quite different. For dataflow the alternative composition uses +~~> arrows, whereas for message reception each alternative starts with case We can largely unify the syntaxes, but maybe not totally. I propose the following forms:
a ~~> s ?a ~~> s ?!a ~~> s Here
> stands for arrow variations, with alternative flows (+>) and parameter specifications ((p:AType)>). But without arrows that have a / inside, which do the exception handling, since there are no such exceptionsa is a simple Scala expression (as already allowed as script expression term), but having static type ActorRef
The first form is for receiving a message from a specific actor a. The second form accepts any actor as sender, and assigns the reference to a. The third form is valid when a is an adapting parameter in the enclosing script.
It should even be possible to have an extra check on the sender, like what is allowed for output parameters:
?a ?if (mySet.contains:a) ~~> s I got this idea because I was not entirely satisfied with this example that I have used on presentations:
class DataProxy(dataStore: ActorRef) extends SubScriptActor {
script live =
<< req: InfoRequest ==> {dataStore ? req} ~~(data :Data )~~> {dataStore ? DetailsRequest:data} ~~(details:Details)~~> {! sender ! (data, details)!} >> ...
} Two different kinds of arrows, and the bracket pair: unnice. I would rather write:
class DataProxy(dataStore: ActorRef) extends SubScriptActor { var requester: ActorRef
script live =
?requester ~~(req : InfoRequest)~~> {dataStore ? req} ~~(data : Data )~~> {dataStore ? DetailsRequest:data} ~~(details: Details )~~> do requester ! (data, details) ...
} Note that I used the word do at the end. This is another new proposal; it is like let, but it creates a normal code fragment (atomic action) instead of a tiny one. Maybe in this case a tiny code fragment would be appropriate as well; I am not sure.
— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/scala-subscript/subscript/issues/41
I do not completely get your point. Could you give a complete command line application (5 to 10 lines long), old style vs new style that you now propose, so that I can compare the two?
import subscript.language
import subscript.Predef._
import subscript.SubScriptApplication
object Main extends SubScriptApplication {
script live = println("Hello, ???")
}
vs
import subscript.language
import subscript.Predef._
import subscript.SubScriptApplication
object Main extends SubScriptApplication {
script live = ?source ~~(args: Array[String])~~> println("Hello, " + args.head)
}
or vs
import subscript.language
import subscript.Predef._
import subscript.SubScriptApplication
object Main extends SubScriptApplication {
script..
live = ?source ~~(args: Array[String])~~> ^args.head ~~> printStuff
printStuff = ?source ~~(name: String)~~> println("Hello, " + name)
}
As for the ?a
and ??a
syntax: I think these should just be syntactic sugar.
The preprocessor currently packs such occurrences in ActualOutputParameter
, ActualConstrainedParameter
and ActualAdaptingParameter
.
This is done when the expression is inside a script parameter list,
but such ?
-expressions etc (also with ?if
and ??
) should also be allowed as terms in script expressions. I think that is not supported yet, so I just created #43.
Then I think for the context of Akka actors we just need to write an implicit script that has an ActorRef as an adapting parameter:
implicit script convertActorRefToScript(?a: ActorRef): Any = ????
I am not sure yet what should be inside ????
. As I wrote earlier, this will want to access the dataflow arrow, to see what kind of parameters are accepted in the partial function/script. This is a runtime decision, done in SubScriptActor
:
callHandlers.collectFirst { case handler if handler isDefinedAt msg => handler(msg) }
I am also not sure how easy this access would be to implement.
And maybe a special declaration annotation for convertActorRefToScript
could be possible, to ensure at compile time that such calls can only occur at the LHS of a dataflow.
Then I think we do not need any specific syntactical handling for actors any more.
About your new code snippets: I still don't get it. Could you first update the code with declarations for the source variable? In the third snippet: do you mean 2 different variables? What should their values become at runtime?
Assuming there is no real need for ?source
in the printStuff
definition, I rather write that as a normal script. Note that the simple arrow ~~>
at the right on the first line expects a parameterized lambda at the RHS. So is printStuff
if you don't specify the actual parameter.
script..
live = ?source ~~(args: Array[String])~~> ^args.head ~~> printStuff
printStuff(name: String) = println("Hello, " + name)
BTW In analogy to what is possible for Scala methods, the latter would almost be equivalent to a lambdaesque declaration:
def printStuff = (name: String) ==> println("Hello, " + name)
which is equivalent to:
def printStuff = (name: String) => [println("Hello, " + name)]
Type is String => Script[Unit]
or maybe in the future: String ==> Unit
.
But maybe we should drop all ==>
syntax, or mark it as "strictly experimental".
At compile time the search for implicit conversions in the LHS for those parts that constitute the lambda's result, should ideally not just be for conversions into a normal Script[_]
, but take into account that a value is required for a dataflow LHS.
At run time everything inside the LHS of a dataflow arrow should be able to easily access the partial function that is implied by the dataflow arrow.
It is even a bit more complicated:
normally, the LHS of ~~>
must yield a result of a type that is acceptable for the partial function that is defined by the arrow; or the arrow may just define values, while the types thereof is inferred.
an implicit conversion for an ActorRef will want to do things differently; it wants to make sure the message is only received when that yields data accepted by the dataflow arrow. Maybe this can be enforced by a macro annotation.
It is comparable to the classic key
script. This only wants to accept a KeyPressed event when the actual parameter is an output parameter, or, in case it is constrained, when the constraint matches. This behavior is implemented with the help of wrappers such as ActualConstrainedParameter.
For the LHS of dataflows we need something similar, but this will be more difficult since there is some distance between the arrows and the LHS. E.g. we would even want to enable:
[a1 + a2] ~~> s
I think I have a good part of a solution:
We create a new type/class/trait: subscript.DataflowSource
.
The compiler will eventually rewrite this to Any
.
An implicit conversion SomeType => Script[DataflowSource]
will only be carried out if either
Script[DataflowSource]
is expected, ora
and b
in a~~>s
and [a+b]~~>s
.A dataflow arrow normally does some type checking: normally the LHS should have a result type that is a subtype of the things that the partial function of the arrow expects.
However, if the LHS result type is DataflowSource
then this check is not done.
To compensate, the DataflowSource
conversion script should at run time query an API (TBD) about the dataflow arrow; and what types are acceptable, so that it only performs its receive action if handler isDefinedAt msg
.
The overall effect should be similar as with the key
script, see my previous comment.
I am not sure anymore whether this is a real solution. Is it possible to create for instance
implicit script convertActorToMessageReceive(??a: ActorRef): DataflowSource
so that this can have anything as a result value?
Even if we will rewrite DataflowSource
to Any
, would we be able to set the result value to whatever we want? I think so, possibly with casting, but we need to try this out.
I have implemented all the functionality except ?!a ~~> s
(see updated PingPong). What exactly should ?!a
do? If it has something to do with the AdaptingParameters, what exactly are they, why can't we do with just OutputParams? What is the generic behaviour of ?!
syntax, outside the scope of actors?
That is my fault; long ago ?!
denoted adapting parameters; now it is ??
.
I will update this in the previous text.
Can you please provide a full example of their usage? In scope of actors and outside of it. I understand that OutputParams are like C++ pointers, but I have a very vague idea of the AdaptingParams. On May 12, 2016 4:16 PM, "André van Delft" notifications@github.com wrote:
That is my fault; long ago ?! denoted adapting parameters; now it is ??. I will update this in the previous text.
— You are receiving this because you commented.
Reply to this email directly or view it on GitHub https://github.com/scala-subscript/subscript/issues/41#issuecomment-218753524
A few weeks ago I read a piece on (or via) Reddit or so, that argued that programming languages should provide full refinement support. This is a good principle. SubScript (as well as its predecessor) does so with, among others, adapting parameters.
E.g. there is the key
script in LookupFrame2, which adds a parameter to the library key
script:
implicit script vkey(??k: Key.Value) = vkey2: top, ??k
I don't have an example for dataflow at hand, and in particular not for actors, but there will surely come up one at some time.
This was the article. Excerpt:
May 1, 2016
I’d like to coin a term for an old but (to my knowledge) previously nameless idea. When considering the primitive constructs of a programming language, there is a litmus test for evaluating the quality of their design: can I implement a wrapper on top of the construct that looks and behaves exactly the same as the original, modulo the name? Passing this test is a good property for a language construct to have; it means the programmer has the ability to substitute the construct with their own equally powerful ones.
When designing a programming language and you find yourself tempted to add a new construct, ask yourself: can the programmer build similar constructs on top of this? Does it pass the pastiche test?
Good test. But still doesn't explain much about the ?? vars. They don't add to the refinability as far as I can see.
From the key
example, though, I see why they don't work the way I implemented them: you're supposed to pass another formal param to their constructor and not a local var. Strange...
I did not mean "??
vars". But there should be ??
operands.
E.g., suppose the previous implicit script vkey
is in scope, and we want to call it giving a prompt:
script promptKey(??k: Key.Value) = @{prompt: _k}: ??k
where prompt
is a method that gives an appropriate prompt, based on the given actual parameter holder.
The current syntax for actor message reception,
<<
...>>
, has three down sides:sender
is only available for the innermost message.+~~>
arrows, whereas for message reception each alternative starts withcase
We can largely unify the syntaxes, but maybe not totally. I propose the following forms:
Here
~~>
stands for arrow variations, with alternative flows (+~~>
) and parameter specifications (~~(p:AType)~~>
). But without arrows that have a/
inside, which do the exception handling, since there are no such exceptionsa
is a simple Scala expression (as already allowed as script expression term), but having static typeActorRef
The first form is for receiving a message from a specific actor
a
. The second form accepts any actor as sender, and assigns the reference toa
. The third form is valid whena
is an adapting parameter in the enclosing script.It should even be possible to have an extra check on the sender, like what is allowed for output parameters:
I got this idea because I was not entirely satisfied with this example that I have used on presentations:
Two different kinds of arrows, and the bracket pair: unnice. I would rather write:
Note that I used the word
do
at the end. This is another new enhancement proposal (https://github.com/scala-subscript/subscript/issues/41);do
is likelet
, but it creates a normal code fragment (atomic action) instead of a tiny one. Maybe in this case a tiny code fragment would be appropriate as well; I am not sure.