Renaming reset/shift in Scala

292 views
Skip to first unread message

Eric Kolotyluk

unread,
Oct 4, 2012, 11:49:19 PM10/4/12
to scala-debate
This is a spinoff from the Visualizing Continuations discussion. The proposal is to replace

  reset {
    . . .
    shift { k: (type1 => type) =>
      . . .
    }
    . . .
  }

with

  delimit {
    . . .
    capture { continuation: (type1 => type2) =>
      . . .
    }
    . . .
  }

There seems to be converging consensus with delimit/capture, but some people prefer 'continue' over 'continuation'. Can we reach a consensus on this?
  1. delimit/capture would replace reset/shift in the Scala compiler continuations plug-in. People could always switch back to reset/shift via the Scala 'import' statement, but the default delimit/capture would encourage people to write more readable code
  2. The use of 'continuation' or 'continue' is really just a convention, but hopefully people would choose to use it instead of 'k', 'cont' or other less readable names.
  3. In the future people would be encouraged to use the new names in lessons and examples of delimited continuations in Scala, especially in an industrial sense, in order to make it easier for newcomers to grasp or even grok continuations.
Given the abstruseness of continuations conceptually, it seems to make sense for people to favor readability and teachability over conciseness or any legacy of research narratives.

Is there any further discussion on this? Can people please vote either +1, 0, -1 on this, and/or state whether you prefer 'continuation' or 'continue' for the function name as a convention.

Cheers, Eric

Ivan Todoroski

unread,
Oct 5, 2012, 12:09:10 AM10/5/12
to Eric Kolotyluk, scala-debate
On 05.10.2012 05:49, Eric Kolotyluk wrote:
> delimit {
> . . .
> capture { continuation: (type1 => type2) =>
> . . .
> }
> . . .
> }
>
> There seems to be converging consensus with delimit/capture, but some
> people prefer 'continue' over 'continuation'. Can we reach a consensus
> on this?

Big +1 on delimit/capture.

Not so sure about "continuation" though, seems a bit of a mouthful to
type. Also not so keen on "continue" due to the potential for confusion
with the eponymous Java/C/C++ keyword. I think simply "cont" might be
best, it's mnemonic enough without being too intrusive.


delimit {
. . .
capture { cont: (A => B) =>
. . .
}
. . .
}


Doesn't look too bad...

In any case, just renaming reset/shift to delimit/capture is already a
huge improvement in itself, regardless of what the continuation
parameter ends up being called in examples/docs.

Marius Danciu

unread,
Oct 5, 2012, 4:57:37 AM10/5/12
to Ivan Todoroski, Eric Kolotyluk, scala-debate
+1 ... does it really matter if it's continuation or continue since this is a function parameter name and this name is not part of the API. Or perhaps I'm missing something.

Marius

John Nilsson

unread,
Oct 5, 2012, 8:02:12 AM10/5/12
to Eric Kolotyluk, scala-debate

+1
I also like continuation

BR
John

Rex Kerr

unread,
Oct 5, 2012, 8:09:51 AM10/5/12
to Eric Kolotyluk, scala-debate
+1, and cont > continuation >>> continue

Continue is a horrible conceptual clash with the keyword from C/Java.

  --Rex

Matthew Pocock

unread,
Oct 5, 2012, 8:54:22 AM10/5/12
to Rex Kerr, Eric Kolotyluk, scala-debate
+1

The thing passed into the shift/capture block is a function, so really should be named as a verb. I realise we can each name it however we like, but for the sake of consistency, it is useful to have some rules of thumb. Using K is just about as bad as bad can be - when it isn't meaningless and non mneumonic, it looks like the K combinator from SKI calculus (≈ const in lambda), which really is not the right semantics at all. If we're going with the cont* theme, I'd prefer continueWith.

  delimit {
    . . .
    capture { continueWith: (type1 => type2) =>
      . . .
      continueWith(x)
      . . .
    }
    . . .
  }

Matthew
--
Dr Matthew Pocock
Integrative Bioinformatics Group, School of Computing Science, Newcastle University
skype: matthew.pocock
tel: (0191) 2566550

√iktor Ҡlang

unread,
Oct 5, 2012, 10:18:12 AM10/5/12
to Matthew Pocock, Rex Kerr, Eric Kolotyluk, scala-debate
import scala.util.continuations.{shift => capture, reset => delimit} ?

Cheers,
--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Eric Kolotyluk

unread,
Oct 5, 2012, 12:31:31 PM10/5/12
to scala-debate
Summary so far:

5 +1's
2 did not vote

There are good reasons for not using 'continue' as the function name.

There is some concern about the function name being a mouthful to type. In the days of Unix, PDP 8's, and teletype model 33 there were some good reasons for avoiding long names. As of 2012, I think it is more important to worry about readability than how long names are. Also, from what other have said, continuations are not widely used, so we would not be typing the function name all that often, and some of us would likely be using copy/paste :-)

The importance of choosing a good naming convention is to make for a good learning experience for every newbie who comes across coded they have never seen before, and more especially when such code is textbook code used in examples. If you are an L3 developer writing libraries, and you know you are the only one who will ever read that code, then the function name probably does not matter that much. However, if other people may have to come along later, and heaven forbid fix a defect you created, then leaving behind code where the intent of the code is as clear as possible becomes increasingly relevant.

Someone suggested 'continueWith' as the name of the function because it is a verb. I personally like the idea. That would give us

  delimit {
    . . .
    capture { continueWith: (type1 => type2) =>

      . . .
    }
    . . .
  }

Are then any strong objections with 'continueWith' as the function name?

Cheers, Eric

nicola...@gmail.com

unread,
Oct 5, 2012, 1:37:45 PM10/5/12
to Eric Kolotyluk, scala-debate
-1 I think we should think to their official names.

continue is bad for the overloaded meaning.
continueWith is too long.
The right word is continuation. It is a very much accepted word for
that concept.
It even has its Wikipedia page

http://en.wikipedia.org/wiki/Continuation
--
Sent from an IBM Model M, 15 August 1989.

Michael Schmitz

unread,
Oct 5, 2012, 1:39:50 PM10/5/12
to nicola...@gmail.com, Eric Kolotyluk, scala-debate
continueWith vs continuation
12 characters each

nicola...@gmail.com

unread,
Oct 5, 2012, 1:44:01 PM10/5/12
to Michael Schmitz, Eric Kolotyluk, scala-debate
continueWith has not the right meaning. You are not continuing the
other program,
(this is not a call/cc or a coroutine), you are applying the continuation.

Jan Vanek

unread,
Oct 5, 2012, 2:04:34 PM10/5/12
to scala-...@googlegroups.com
But it sounds better if it is a verb. If you do say coll.insert(..), you
call a method, but the method is not called insertion...

It's a parameter anyway, if I understand it, we can call it however we
want. It would be nice though, if we could do:

delimit {
..
capture {
.. cont("one")
}
}

But I'm afraid it is not realizable. There we would need fixed/good name.

With regards,
Jan

Eric Kolotyluk

unread,
Oct 5, 2012, 3:57:45 PM10/5/12
to scala-debate
Might as well share with everyone...

I am fine with either 'continuation' or 'continueWith' but would favor what ever is more accurate semantically, and I am not hung up on the function name being a verb.

Cheers, Eric

On Fri, Oct 5, 2012 at 12:28 PM, Jan Vanek <j3v...@gmail.com> wrote:
On 05.10.2012 20:45, Eric Kolotyluk wrote:
I am fine with either 'continuation' or 'continueWith' but would favor what ever is more accurate semantically, and I am not hung up on the function name being a verb.


Hi Eric,
that's right, that's more important. Btw. you sent it to me only...
Regards,
Jan


Cheers, Eric

Som Snytt

unread,
Oct 5, 2012, 5:44:06 PM10/5/12
to Eric Kolotyluk, scala-debate
On Fri, Oct 5, 2012 at 9:31 AM, Eric Kolotyluk <eric.ko...@gmail.com> wrote:
Summary so far:

5 +1's
2 did not vote


-1 to any name change.

First of all, someone would have to edit Figure 1 in the continuations paper, which is the only reliable documentation.  (Pace the excellent scaladoc and dcsobral.blogspot.)

As for macros, there's no incentive to make continuations too easy to undertake.  (As I learned by answering someone's cps question on SO.)

It's called shift because all your code is shifted right an extra tab.

I may as well call a spade a spade and the hole in my computation a hole. 

And am I the only one who uses it this way?

hole(fun = plug(input) _)

It's called fun because it's so darn fun!

I agree that k is bad for the "continuation object".  Kappas should be kappas and lambdas should be lambdas. 

I'm not a fan of reset, because it sounds like the cart is coming before the horse, but I like delimit less.  I may import it as "prompt" or, more germanely, "scala_>".

import scala.util.continuations.{ reset => scala_>, shift => hole, _ }

// continuation processor, the "plug" that fills the "hole" in my computation.
def plug(input: Try[String])(@deprecatedName('k) κ: (Boolean => Int)): Int = ???

def f: Int = scala_> {
  hole(fun = plug(input) _)
}



Eric Kolotyluk

unread,
Oct 5, 2012, 6:13:56 PM10/5/12
to scala-debate
OK, that is the first -1 so far to the name change.

There are certainly going to be problems with a name change, but how can we mitigate such changes?

Would it be reasonable for a time that the continuations plugin accept 'delimit' as a synonym for 'reset,' and 'capture' as a synonym for shift?'

As for existing documentation, papers, blogs, etc., there is certainly going to be confusion for a while, which can be mitigated with increased awareness through dialog.

hole/plug are definitely cute, and great for explanations, but seem less clear to me overall than delimit/capture/continuation.

Cheers, Eric

Jan Vanek

unread,
Oct 6, 2012, 3:59:23 AM10/6/12
to scala-...@googlegroups.com

 capture {
    . . .
    release { cont: (type1 => type2) =>
      . . .
    }
    . . .
 }

The meaning is, I want to capture a piece of code starting at "capture", and I want to release or let-go the up-to-now-captured continuation in the block of code starting at "release".

I think it is closer to the reset/shift. The problem with delimit/capture is that the capture works "backwards", it captures the continuation up/back to delimit, that is true and correct, but what is important is the code inside the capture, where the continuation is used, and this code (inside the capture) is not captured at all.

With regards,
Jan

Eric Kolotyluk

unread,
Oct 6, 2012, 12:26:44 PM10/6/12
to scala-...@googlegroups.com
Am I mistaken? I thought that shift { } captures the line of code that contains 'shift' and the rest of the code to the end of the reset { } block,  not from the beginning of the reset { } block. In particular

reset {
  . . .
  val foo = shift {

    . . .
  }
  . . .
  val bar = shift {

    . . .
  }
  . . .
}

the second shift { } is not going to capture the first shift { }. At least that is the way I thought it worked.

I do admit that in

delimit {
  . . .
  /*start of capture*/ val foo = capture {
    . . .
  }
  . . . /* end of capture */
}

it is not immediately obvious that  'val foo =' until the end of the delimit is what is being captured, but I cannot think of any clearer way to express that, except by adding the comments.

Cheers, Eric

Ivan Todoroski

unread,
Oct 6, 2012, 1:17:14 PM10/6/12
to √iktor Ҡlang, Matthew Pocock, Rex Kerr, Eric Kolotyluk, scala-debate
On 05.10.2012 16:18, √iktor Ҡlang wrote:
> import scala.util.continuations.{shift => capture, reset => delimit} ?

Yes, but this discussion is about making delimit/capture the default,
and encouraging the use of delimit/capture in examples.

Then the dyed-in-the-wool fans of reset/shift could still use the above
trick in reverse for their code, but the noobs would not be burdened by
meaningless terms.

Ivan Todoroski

unread,
Oct 6, 2012, 1:22:58 PM10/6/12
to Eric Kolotyluk, scala-debate
On 05.10.2012 18:31, Eric Kolotyluk wrote:
> There is some concern about the function name being a mouthful to type.
> In the days of Unix, PDP 8's, and teletype model 33 there were some good
> reasons for avoiding long names. As of 2012, I think it is more
> important to worry about readability than how long names are. Also, from
> what other have said, continuations are not widely used, so we would not
> be typing the function name all that often, and some of us would likely
> be using copy/paste :-)

Agreed, for all the reasons you stated. I withdraw my objection to the
length of the name.


> Someone suggested 'continueWith' as the name of the function because it
> is a verb. I personally like the idea. That would give us

Somehow, I prefer "continuation" to "continueWith"... As others said in
the thread, "continuation" is a standard term for the concept, and it's
not clear that "continueWith" actually reflects what's really going on.

Jan Vanek

unread,
Oct 6, 2012, 1:24:51 PM10/6/12
to scala-...@googlegroups.com
In your example:

def foo() = {
  println("d")
  "zero " + shift{k: (String => String) => k(k(k("one ")))}
}
     
def bar() = {
  println("c")
  foo() + "two "
}
     
def baz() = {
  println("b")
  reset(bar())
}

what is captured as k is a function:

def k(s: String) = ("zero " + s) + "two "

So the code of the continuation k has nothing to do with the block of code inside the shift, it is created from the code outside of the shift. The code which interacts with the shift block (from left and from right), up to the enclosing reset, but "seen" up-to-now, when we start in reset.

On the hand I am partially wrong too, because the println() pieces are obviously not captured in k.



On 06.10.2012 18:26, Eric Kolotyluk wrote:
Am I mistaken? I thought that shift { } captures the line of code that contains 'shift' and the rest of the code to the end of the reset { } block,  not from the beginning of the reset { } block. In particular

reset {
  . . .
  val foo = shift {
    . . .
  }
  . . .
  val bar = shift {
    . . .
  }
  . . .
}

the second shift { } is not going to capture the first shift { }. At least that is the way I thought it worked.

I do admit that in

delimit {
  . . .
  /*start of capture*/ val foo = capture {
    . . .
  }
  . . . /* end of capture */
}

it is not immediately obvious that  'val foo =' until the end of the delimit is what is being captured, but I cannot think of any clearer way to express that, except by adding the comments.



As I said, if anything is captured at all here, it has nothing to do with the code inside the capture {} block, which makes the name counter-intuitive.




Cheers, Eric


With regards,
Jan

Eric Kolotyluk

unread,
Oct 7, 2012, 3:15:56 PM10/7/12
to scala-...@googlegroups.com
Yes, my understanding is that the code inside the shift is not captured. Again, another reason it can be so hard to describe continuations.

And it really helps to show


def k(s: String) = ("zero " + s) + "two "

Someone should write an article about how to teach continuations to others :-)

Cheers, Eric

pagoda_5b

unread,
Oct 8, 2012, 6:43:08 AM10/8/12
to scala-...@googlegroups.com, Rex Kerr, Eric Kolotyluk
I also thought about delimit as a possible name but would prefer:

  capturing {

    . . .
    capture { continuation: (type1 => type2) =>
      . . .
      continuation(x)
      . . .
    }
    . . .
  }

The ratio is that capturing delimits the context of what you're actually capturing with the capture call.
I resent using a name other than continuation, mostly because that's the name used in most theoretical papers for the whole subject (we talk about continuations, continuation monad, continuation plugin....) so it doesn't makes much sense to me to use any other.

The capturing vs delimit issue is minor here, I have preferences but I agree for delimit as a reasonable choice, so both forms are +1 for me.



On Friday, October 5, 2012 2:54:24 PM UTC+2, Matthew Pocock wrote:

The thing passed into the shift/capture block is a function, so really should be named as a verb.

I don't agree that it needs be a verb, since it represents the captured context of execution flow, that I can re-execute at will by applying it to whatever arguments I need at the moment.

 
Thanks, Ivano

nicola...@gmail.com

unread,
Oct 8, 2012, 1:13:16 PM10/8/12
to pagoda_5b, scala-...@googlegroups.com, Rex Kerr, Eric Kolotyluk
> I don't agree that it needs be a verb, since it represents the captured
> context of execution flow, that I can re-execute at will by applying it to
> whatever arguments I need at the moment.
>

+1

Shelby

unread,
Nov 5, 2012, 10:30:54 PM11/5/12
to scala-...@googlegroups.com
+1 on a name change, because we want to explain this for mainstream programmers (not researchers since they are the outlier minority in our desired audience) in terms of what the plugin transformation does to the code, i.e. the mechanics, and not w.r.t. some greater theory of CPS. Researchers can do an import to regain reset/shift/continuation and suffer no harm.

I attempted to explain the mechanics of the transformation abstraction succinctly and coherently:


Given that we want to teach the mechanics, I think the following terms are much more intuitive.

delimit { 
    ...
    replace { with: ... }
    ....
 }

The mechanics of the transformation does not require that the `with` function call the replaced code. The mechanics only requires that the code is replaced with the function.

Any call to the replaced code is up to the programmer of the `with` (continuation) function, i.e. due to a separation-of-concerns our naming choices are not concerned with what the continuation function will do.

The above name suggestions do not convey that the replaced code is also captured (moved to) a callback of type given by the input parameter type of the continuation function. So therefore I might instead suggest:

delimit { 
    ...
    capture { replacement: ... }
    ....
 }

However, the type signture of the `with` function dictates that it is going to receive a callback to the replaced code and replace/with is very intuitive when explaining the mechanics of the transformation, thus I prefer my first suggestion over the capture/cont... or capture/replace... syntax.

Shelby

unread,
Nov 5, 2012, 10:43:05 PM11/5/12
to scala-...@googlegroups.com
Excuse me, I screwed up. The continuation function is the callback to the replaced code. The `with` would be the anonymous function that is not named in our terse naming examples. Please read my explanation of the transformation mechanics to see where I am coming from conceptually:

http://stackoverflow.com/questions/1512930/what-are-scala-continuations-and-why-use-them/13236109#13236109

Thus, I change my suggested names to:

delimit { 
    ...
    replaceWith { replaced: ... }
    ....
 }

Or:

delimit { 
    ...
    replaceWith { captured: ... }
    ....
 }

Or much better, I prefer for clarity the convention of always naming the anonymous function:

def with( replaced: ... ) ...
delimit { 
    ...
    replace { with }
    ....
 }

Or:

def with( captured: ... ) ...
...

Shelby

unread,
Nov 6, 2012, 12:14:19 AM11/6/12
to scala-...@googlegroups.com
@nafg reminded me in a comment that `with` is a keyword, so I proposed `replacement` or `substitute` instead.

def replacement( replaced: ... ) ...
delimit { 
    ...
    replace { replacement }
    ....
 }

Isn't that mechanically much more obvious?

No theory of continuations or CPS, just pure mechanics of what it does at the code abstraction level. Which is all the programmer really cares about it when learning it.

Shelby

unread,
Nov 6, 2012, 3:15:40 AM11/6/12
to scala-...@googlegroups.com
Correction. I am assuming of course that reset/shift are functions in a library and those blocks are the short-hand for a closure, i.e. anonymous function. Been a while since I studied that closure syntax, so please correct me if necessary. The less used idiosyncrasies of Scala syntax can escape the mind after a year or so of not using them...

def replacement( replaced: ... ) ...
delimit { 
    ...
    replace(replacement)
    ....
 }

Shelby

unread,
Nov 7, 2012, 3:31:48 AM11/7/12
to scala-...@googlegroups.com
The clarity of mechanics I am proposing, doesn't require naming the anonymous function:

delimit { 
    ...
    ... = replacement( replaced: (... => ...) = ... )
    ...
 }

Or `substitute` is one character shorter than `replacement`.

I strongly prefer those over `capture`, because `capture` could imply that it is capturing it's input parameter, which is not what it does. The input parameter is the replacement for what is being captured and replaced. The disadvantage of a more verbose named argument provides the benefit that the action is a verb.

delimit { 
    ...
    ... =  capture( replacement = replaced: (... => ...) => ... )
    ...
 }

And in that case, isn't `replace` more specific to the action being done?

delimit { 
    ...
    ... = replace( replacement = replaced: (... => ...) => ... )
    ...
 }

But the result returned from `capture` or `replace` is not a capture nor a replace object, so the above verbosity makes no sense to me when I read it, yet it isn't the replacement object either. The result returned is the input to the `replaced` callback. So perhaps the most intuitive is the convention:

delimit { 
    ...
    ...  = replacedInput( replacement = replaced: (... => ...) => ... )
    ...
 }

Which can optionally be expressed by the convention:

def replacement( replaced: ... => ... ) ...
delimit { 
    ...
    ...  = replacedInput( replacement )
    ...
 }

The more verbose `inputOfReplaced` is more clear.

The reason we can agree to not use verbs for these functions, is because the control has been inverted, thus the normal action meaning of a function has been inverted to value ("don't call me, I will read you").

I slightly prefer `replaced` over `cont...`, because of the symmetry. And it clarifies the mechanical code transformation, instead of clarifying the action that it does. For a novice not knowing anything else about how this works and just eyeballing the syntax (also readiness of recall when eyeballing long after learning and forgetting a concept), calling the `replaced` code obviously continues what was replaced, but calling the `continue` code doesn't obviously say what code is continued.
Reply all
Reply to author
Forward
0 new messages