Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: Misc Compiler
    • Labels:
      None
    • Environment:

      lazy parameter

      Description

      For now, we only have call-by-name parameters. We should allow the lazy modifier on parameters, for instance:

      def f[a](lazy t: a) = {
       ..
      }
      

      The meaning should be equivalent to:

      def f[a](t': => a) = {
        lazy val t: a = t'
        ..
      }
      

        Issue Links

          Activity

          Hide
          Jason Zaugg added a comment -

          Given that to make make that case work, we have to perform the rewriting at the call site, should we do it there in all cases? One disadvantage: changing `=> A` to `lazy A` would require recompilation of client code (although it would appear to be binary compatible.)

          We've been burned so often by unforseen (although not unforseeable) feature interactions (think Value Classes). So I'm naturally cautious with this sort of thing.

          Show
          Jason Zaugg added a comment - Given that to make make that case work, we have to perform the rewriting at the call site, should we do it there in all cases? One disadvantage: changing `=> A` to `lazy A` would require recompilation of client code (although it would appear to be binary compatible.) We've been burned so often by unforseen (although not unforseeable) feature interactions (think Value Classes). So I'm naturally cautious with this sort of thing.
          Hide
          Ryan Hendrickson added a comment -

          Not sure what you mean by ‘do it there in all cases’; my assumption was that any time we would rewrite the call site to use vals to capture arguments, if the parameter in question was marked lazy, we'd capture its argument with a lazy val instead. Did you have additional cases in mind?

          It is a good point about the binary-but-not-really compatibility of a function taking `=> A` and a function taking `lazy A`, but only if there are subsequent parameter lists and default arguments. My low-confidence guess is that practically, it wouldn't cause real issues that often—I at least am pretty used to having to recompile all client code regardless of the binary compatibility of dependencies, given how implicit resolution might change—but I defer to your experience.

          Show
          Ryan Hendrickson added a comment - Not sure what you mean by ‘do it there in all cases’; my assumption was that any time we would rewrite the call site to use vals to capture arguments, if the parameter in question was marked lazy, we'd capture its argument with a lazy val instead. Did you have additional cases in mind? It is a good point about the binary-but-not-really compatibility of a function taking `=> A` and a function taking `lazy A`, but only if there are subsequent parameter lists and default arguments. My low-confidence guess is that practically, it wouldn't cause real issues that often—I at least am pretty used to having to recompile all client code regardless of the binary compatibility of dependencies, given how implicit resolution might change—but I defer to your experience.
          Hide
          Johannes Rudolph added a comment -

          The "additional case" would be the original one where the rewriting was done in the method and not at the call site.

          Show
          Johannes Rudolph added a comment - The "additional case" would be the original one where the rewriting was done in the method and not at the call site.
          Hide
          Ryan Hendrickson added a comment -

          Ahhh, I see. Mmm. I don't know; it's not as if it's incorrect to have the rewriting at the call site when necessary and also in the method in all cases, just a bit wasteful.

          Also, consider eta-expansion:

          def foo(lazy a: Int) = { a; a }
          val f = foo _
          

          f should have type (=> Int) => Int (I think; unless we're reforming how call-by-name types work), but the lazy semantics should be preserved so that a is evaluated only once. Either the rewrite is internal, or the eta-expansion gets complicated.

          Similarly, can we allow anonymous functions to have lazy arguments, given that we already permit them to have call-by-name?

          val f: (=> Int) => Int = (lazy a) => { a; a }
          
          Show
          Ryan Hendrickson added a comment - Ahhh, I see. Mmm. I don't know; it's not as if it's incorrect to have the rewriting at the call site when necessary and also in the method in all cases, just a bit wasteful. Also, consider eta-expansion: def foo(lazy a: Int) = { a; a } val f = foo _ f should have type (=> Int) => Int (I think; unless we're reforming how call-by-name types work), but the lazy semantics should be preserved so that a is evaluated only once. Either the rewrite is internal, or the eta-expansion gets complicated. Similarly, can we allow anonymous functions to have lazy arguments, given that we already permit them to have call-by-name? val f: (=> Int) => Int = (lazy a) => { a; a }
          Hide
          Ryan Hendrickson added a comment -

          Also-also, that call-site rewriting really screws with type inference, so I'd really rather not introduce it into any new cases if we don't have to.

          Show
          Ryan Hendrickson added a comment - Also-also, that call-site rewriting really screws with type inference, so I'd really rather not introduce it into any new cases if we don't have to.

            People

            • Assignee:
              Hubert Plociniczak
              Reporter:
              Iulian Dragos
              TracCC:
              Caoyuan Deng, Carlos Lopez, Daniel Sobral, Eric Torreborre, Ismael Juma, Jason Zaugg, Johannes Rudolph, Matthew Pocock, Sbastien Bocq, Seth Tisue
            • Votes:
              12 Vote for this issue
              Watchers:
              18 Start watching this issue

              Dates

              • Created:
                Updated:

                Development