scala-subscript / subscript

9 stars 2 forks source link

Syntax for implicit conversion of output parameters, constrained parameters and adapting parameters #43

Open AndreVanDelft opened 8 years ago

AndreVanDelft commented 8 years ago

As for the syntax: I think these should just be syntactic sugar. The preprocessor currently packs occurrences of ?a, ?a ?if(...) and ??a in ActualOutputParameter, ActualConstrainedParameter and ActualAdaptingParameter. This is done when the expression is inside a script parameter list, not yet as terms in script expressions awaiting an implicit conversion. Well, I am not sure; I think that is not supported yet.

So with an implicit script key(??c: Int) we should be allowed to write:

key:?c
key:?c ?if isUppercase:c
key:??c (adapting parameter)

and with implicit conversions:

?c
?c ?if isUppercase:c
??c  
AndreVanDelft commented 8 years ago

And ideally it should be possible to write ?c:Int and c:Int ?if (...)

This would also declare the local variable c, and make it visible in the rest of the sequence where this occurs (if there is no such sequence visible, then a sequence of length 1 is assumed).

AndreVanDelft commented 8 years ago
?a: ActorRef ~~> s
t

Here the declared value a should not only be visible in t (see my previous comment), but also in s.

AndreVanDelft commented 8 years ago

The foregoing may be relatively easy to implement, except maybe for the requirement expressed in the previous section. To keep things simple, let's drop this requirement.

The main problem seems to be: what kind of variable declaration should this be equivalent with? Distinguish the following cases:

AndreVanDelft commented 8 years ago

This test is a bit wrong:

  "Constrained params" should "work" in {
    implicit script param2script(??x: Int) = let x = 10

    script foo =
      var bar = 3
      ?bar ?if (bar > 0)
      ^bar

    foo.e shouldBe Success(10)    

Within param2script it should be possible to check that the formal parameter matches the actual one. This is done with FormalParameter.matches(value). Later, when the script call is about to succeed, the same test will be done again. Note that at that point the formal parameter value has not yet been transferred to the actual parameter. In the code above bar is still 3. A slightly better test would be ?if (bar >= 10); this test would fail, which is in a way good, because it is wrong. The current test succeeds while it is wrong, and that is worse. The test should not use the variable bar, but a placeholder: ?if (_ >= 10).

AndreVanDelft commented 8 years ago
  "Output params" should "be usable from a script" in {
    implicit script param2script(?x: Int) = let x = 10

    script foo =
      var bar = 3
      ?bar
      ^bar

    foo.e shouldBe Success(10)
  }

This does not yet use the syntax ?a:T. So the test (or a new test) should become:

  "Output params" should "be usable from a script" in {
    implicit script param2script(?x: Int) = let x = 10

    script foo =
      ?bar: Int
      ^bar

    foo.e shouldBe Success(10)
  }
anatoliykmetyuk commented 8 years ago

"matches" is available from the implicit script. Can you please write a new test or modify the existing one so that it tests the feature in question and fails? On May 13, 2016 11:16 PM, "André van Delft" notifications@github.com wrote:

This test is a bit wrong:

"Constrained params" should "work" in { implicit script param2script(??x: Int) = let x = 10

script foo =
  var bar = 3
  ?bar ?if (bar > 0)
  ^bar

foo.e shouldBe Success(10)

Within param2script it should be possible to check that the formal parameter matches the actual one. This is done with FormalParameter.matches(value). Later, when the script call is about to succeed, the same test will be done again. Note that at that point the formal parameter value has not yet been transferred to the actual parameter. In the code above bar is still 3. A slightly better test would be ?if (bar >= 10); this test would fail, which is in a way good, because it is wrong. The current test succeeds while it is wrong, and that is worse. The test should not use the variable bar, but a placeholder: ?if (_ >= 10) .

— You are receiving this because you modified the open/close state. Reply to this email directly or view it on GitHub https://github.com/scala-subscript/subscript/issues/43#issuecomment-219148424

AndreVanDelft commented 8 years ago

That should be like:

"Constrained params" should "work" in {

    var doesMatch = false
    var hadDeadlock = false

    implicit script param2script(??x: Int) = let {x = 1; doesMatch = _x.matches}

    script foo =
      var bar = 0
      do ?bar ?if (_ > 2) else let hadDeadlock=true
      ^bar

    foo.e shouldBe Success(0)
    doesMatch shouldBe false
    hadDeadlock shouldBe true
AndreVanDelft commented 8 years ago

In C# 7.0 such parameters will be called "out variables". We may learn from those:

Out variables

Currently in C#, using out parameters isn’t as fluid as we’d like. Before you can call a method with out parameters you first have to declare variables to pass to it. Since you typically aren’t initializing these variables (they are going to be overwritten by the method after all), you also cannot use var to declare them, but need to specify the full type:

public void PrintCoordinates(Point p)
{
    int x, y; // have to "predeclare"
    p.GetCoordinates(out x, out y);
    WriteLine($"({x}, {y})");
}

In C# 7.0 we are adding out variables; the ability to declare a variable right at the point where it is passed as an out argument:

public void PrintCoordinates(Point p)
{
    p.GetCoordinates(out int x, out int y);
    WriteLine($"({x}, {y})");
}

Note that the variables are in scope in the enclosing block, so the subsequent line can use them.

Most kinds of statements do not establish their own scope, so out variables declared in them are usually introduced into the enclosing scope.

Note: In Preview 4, the scope rules are more restrictive: Out variables are scoped to the statement they are declared in. Thus, the above example will not work until a later release.

Since the out variables are declared directly as arguments to out parameters, the compiler can usually tell what their type should be (unless there are conflicting overloads), so it is fine to use var instead of a type to declare them:

p.GetCoordinates(out var x, out var y);

A common use of out parameters is the Try... pattern, where a boolean return value indicates success, and out parameters carry the results obtained:

public void PrintStars(string s)
{
    if (int.TryParse(s, out var i)) { WriteLine(new string('*', i)); }
    else { WriteLine("Cloudy - no stars tonight!"); }
}

Note: Here i is only used within the if-statement that defines it, so Preview 4 handles this fine.

We plan to allow “wildcards” as out parameters as well, in the form of a *, to let you ignore out parameters you don’t care about:

p.GetCoordinates(out int x, out *); // I only care about x

Note: It is still uncertain whether wildcards make it into C# 7.0.