Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended forward() for using in closure #805

Merged

Conversation

PhucVH888
Copy link
Contributor

Introduction

To recall, the forward is designed to delegate the future and to be fulfilled by other delegated method. In summary, forward can be used in the following four cases.

  1. DONE: forward MethodCall (Adding a forward to Encore #682)
  2. DONE: forward FutureChaining (Extended forward #784)
  3. DONE: forward PreexistingFuture (Extended forward #784)
  4. forward in closure's body

In this PR, the forward() can be used in closure.

Syntax

4. forward(arg ~~> fun () => forward(tmp)

Semantics

4. forward in closure's body

      forward(f ~~> fun(x:int) => forward(g))

where f and g are preexisting futures.

class Base
  def one(g : Fut[int]) : int
    forward( (new Foo) ! foo() ~~> fun(x : int) => forward(g))
  end
end

Examples

You can find many examples in the src/tests/encore/forward folder.


active class Foo
def foo(arg : Fut[int]) : int
forward(arg ~~> fun(x : int) : int => forward((new Base) ! base()))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why double forward in all the tests?

@supercooldave
Copy link

supercooldave commented May 13, 2017

Here is the basis for the key test case:

fun join[t](ff : Fut[Fut[t]]) : Fut[t]
  ff ~~> (fun (f : Fut[t]) forward(f))
end

This is the function that asynchronously flattens a future of futures.

Could be used like:

active class Foo
  def m() : int
    10
  end

  def bar() : Fut[int]
    this!m()
  end
end

active class Main
  def main() : int
    val foo = new Foo
    val Fut[t] f = join(foo!bar())
    println("{}", get(f))
  end
end

Make it so.

@supercooldave
Copy link

Here is another test case to consider (it can probably be simplified):


active class Main
  def main() : unit
    val fres = this!foo() ~~> (fun (x : int) : int forward(this!inc(x)) end))
    print({}, get(fres))
  end

  def foo() : int
    10
  end
  
  def inc(x : int) : int
    x + 1
  end
end

The point of this is that the return type of the method within which forward appears is different from the return type of the closure forward appears within.

A similar example should be devised for forward inside async.

Copy link

@supercooldave supercooldave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small comments.

let bound = map (ID.qLocal . A.pname) eparams
freeVars = filter (ID.isLocalQName . fst) $
Util.freeVariables bound body
isIdClosure = not . null $ filter (isIdFun . A.pname) eparams

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you checking for the identity function?
This suggests to me that the design is broken somewhere.

@supercooldave
Copy link

supercooldave commented May 29, 2017

The following case does not compile (when used in a larger context):

fun join(ff : Fut[Fut[int]]) : Fut[int]
  forward(ff ~~> (fun (f : Fut[int]) : int => forward(f)))
end

Error is:

 *** Error during typechecking *** 
"join.enc" (line 2, column 14)
Forward cannot be used in functions

But this is a forward inside a closure inside a future chain, which is valid.

@supercooldave
Copy link

supercooldave commented May 29, 2017

If I modify forwardArgInClosure.enc so that join is polymorphic, as follows:

def join[sharable t](ff : Fut[Fut[t]]) : t
  forward(ff ~~> (fun (f : Fut[t]) : t => forward(f)))
end

I get the error

 *** Error during typechecking *** 
"join.enc" (line 9, column 53)
Returned type t of forward should match with the result type of the containing method Fut[sharable t]
In expression: 

which suggests that something is wrong in the type checker.

@supercooldave
Copy link

It seems that I get a similar error if I try to use forward inside a chained-closure where the return type is an object type.

For instance,

active class Main
  def main() : unit
    val fres = (this!foo() ~~>  fun (x : int) : int
                                    val bar = new Bar
                                    forward(bar!bar())
                                end)
    await(fres)
    println("{}", get(fres))
  end

  def foo() : int
    42
  end
end

active class Bar  
  def bar() : int
    10
  end
end

will succeed, but if I change the Bar!bar() method to return something of some other type, such as a passive object, it fails. For instance, the following:

active class Main
  def main() : unit
    val fres = (this!foo() ~~>  fun (x : int) : String
                                    val bar = new Bar
                                    forward(bar!bar())
                                end)
    await(fres)
    println("{}", (get(fres)))
  end

  def foo() : int
    42
  end
end

active class Bar  
  def bar() : String
    "Bar"
  end
end

results in error:

 *** Error during typechecking *** 
"dave.enc" (line 5, column 48)
Returned type String of forward should match with the result type of the containing method Fut[String.String]

@PhucVH888 PhucVH888 force-pushed the phuc-extended-forward-last-case branch 2 times, most recently from 261ea83 to 84b763f Compare June 13, 2017 13:04
@PhucVH888 PhucVH888 force-pushed the phuc-extended-forward-last-case branch 2 times, most recently from 219fc4b to d663d81 Compare June 21, 2017 21:03
@PhucVH888
Copy link
Contributor Author

@supercooldave I have fixed the issues and included your test cases. This PR is ready for review, IMO.

@supercooldave
Copy link

I'll have a look.
Did you handle the case of forward in async?

@supercooldave
Copy link

Have you addressed issue #816?

Copy link

@supercooldave supercooldave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A first batch of comments.

@@ -1019,26 +1020,38 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
callTheMethodOneway
ntarget targetType name args typeArguments Ty.unitType

let nullCheck = targetNullCheck ntarget target name emeta "."
let nullCheck = targetNullCheck ntarget target name emeta "!"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this changed from "." to "!"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"!" is used for my own test, but I forgot to recover before pushing the code. It has been fixed in the next commit.

@@ -0,0 +1,58 @@
-- Error related to unknown _enc_type_t in method produce()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clean up the comments in these files = remove them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is irrelevant to the forward. It's accidentally committed.

"This message should never be appeared when calling method green()"
end
end
-- active class Pepper

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented out code, please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is for debugging, be removed. Thanks Dave.

@supercooldave
Copy link

The following test cases don't have a .out:

failedPolyTypeStreamWithObject.enc
forwardReturn.enc
test0613.enc

@supercooldave
Copy link

The follow code should print 10 three times, but it prints 10 only once.


fun join[t](ff : Fut[Fut[t]]) : Fut[t]
  ff ~~> (fun (f : Fut[t]) : t => forward(f))
end

fun intJoin(ff : Fut[Fut[int]]) : Fut[int]
  ff ~~> (fun (f : Fut[int]) : int => forward(f))
end

active class Bar
  def bar() : int
    10
  end
  
  def baz() : Fut[int]
    this!bar()
  end
end

active class Main
  def main() : unit
    val bar = new Bar()
    println("{}", get(bar!bar()))
    println("{}", get(intJoin(bar!baz())))
    println("{}", get(join(bar!baz())))
  end
end

@PhucVH888 PhucVH888 force-pushed the phuc-extended-forward-last-case branch from d663d81 to d99c78e Compare July 12, 2017 10:22
@PhucVH888
Copy link
Contributor Author

@supercooldave : The forward is not allowed to be used in function, it has been checked in the test case forwardFunction.enc. However, the case that forward is nested in the closure is not rejected. I will fixed it.

@PhucVH888
Copy link
Contributor Author

The fix of issue #816 (Forward-Return) has been included in this PR.

@supercooldave
Copy link

supercooldave commented Jul 12, 2017

Are you saying that you won't allow the following?

fun join[t](ff : Fut[Fut[t]]) : Fut[t]
   ff ~~> (fun (f : Fut[t]) : t => forward(f))
end

The test seems to suggest that this is prohibited.
But it should be allowed. Indeed, it is one of the core use case for forward.

If you look at the semantics of forward we were working on, you'll see that this is completely sensible. Firstly, the forward gets translated as follows:

fun join[t](ff : Fut[Fut[t]]) : Fut[t]
   ff ~~> (fun (f : Fut[t]) : t => forward(f ~~> id) )
end

Now the semantics are that the future associated with the outer ~~> is used to catch the result of the inner ~~>.

Copy link

@supercooldave supercooldave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forward inside chaining or inside async should always work, regardless of where the forwarding or chaining occurs.

@@ -0,0 +1,26 @@
fun join[t](ff : Fut[Fut[t]]) : Fut[t]
ff ~~> (fun (f : Fut[t]) : t => forward(f))
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be allowed.


fun intJoin(ff : Fut[Fut[int]]) : Fut[int]
ff ~~> (fun (f : Fut[int]) : int => forward(f))
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be allowed.

@supercooldave
Copy link

It's unclear whether this will be finished.
For the limited scope that this version covers, it does what it should and the code has been reviewed and comments mostly addressed adequately.
I feel it should be accepted before bit rot sets in.

@kikofernandez
Copy link
Contributor

Does this mean that you will maintain forward in Encore?

@supercooldave
Copy link

In the absence of other maintainers, yes.
There are one or two variants that were not implemented that need to be done as well.

@kikofernandez
Copy link
Contributor

I am interested in forward and its use with futures and ParTs. I cannot commit to maintain it in the long run (paternity leave) but, if there is a hackathon soon, we should clarify the remaining work and finish it up

@supercooldave
Copy link

Forward is useful for Encore.
And I think a hackathon should be enough to finish the remaining work.

Don't worry @kikofernandez, I won't ask you to maintain this.

@supercooldave supercooldave merged commit d15496b into parapluu:development Sep 29, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants