lampepfl / dotty-feature-requests

Historical feature requests. Please create new feature requests at https://github.com/lampepfl/dotty/discussions/new?category=feature-requests
31 stars 2 forks source link

begin marker #231

Closed som-snytt closed 1 year ago

som-snytt commented 3 years ago

A long function definition might consist of many short local functions followed by a function body.

An optional begin marker would help locate where the body starts. Often this is marked with a comment.

def f =
  def g = ...
  def h = ...
begin f
  g * h
end f

An alternative idea is to allow additional indentation of the prefix of definitions:

def f =
    def g = ...
    def h = ...
  g * h
end f

That expression is currently badly indented.

Possible restrictions on such syntax might include that only method defs are allowed (or lazy val or templates); the idea is that evaluation begins at the begin.

A related feature request is to make function result value more perspicacious:

def f =
  val x = ...
  ...
  // x but replace this expr, which dangles at the bottom of the body
end f with x

That syntax would allow naming the body:

def f =
  def g = ...
  def h = ...
  def run = g * h
end f with run

but burdens end with runtime semantics.

Alternatives are value.tap(f) and try body finally f as a way to say "here's the result and additional side effects".

Also Begin the Beguine with Thomas Hampson.

LPTK commented 3 years ago

This is starting to look dangerously close to Pascal!

function E(x: real): real;
    function F(y: real): real;
    begin
        F := x + y
    end;
begin
    E := F(3) + F(4)
end;
som-snytt commented 3 years ago

dangerously close to Pascal

image

som-snytt commented 2 years ago

Another underserved use case, as noted at Scanners, is to mark the end of class initialization.

That is, you want C().tap(_.init()) where init is guaranteed to happen after construction, last of all.

The marker could be end as in end <init>, except that it doesn't end a scope, it merely marks that "by now, everything else is initialized and after here, there can be only defs."

Which is the linked ticket on return is:

class Scanner:
   lots of vals
  var currentRegion =
    nextChar()    /* Initialization: read first char, then first token */
    nextToken()
    topLevelRegion()
  end currentRegion
  return  // from constructor!
  def nextToken = ???
  // old location of initialization aka "first side effects"
end Scanner

alternatively

class C:
  begin
  val i = 42
  end begin
  def c = i * 2
end C
som-snytt commented 2 years ago

People like me keep asking for early return support.

A begin block could support early returns as "guard" syntax, such as we are used to in pattern matches and for comprehensions.

begin if n > 0 then

I guess that is one guard, but that is better than none.

I just refactored a if (!initialized) return to def f = if (initialized) { ... } in Scala 2.

In fact, it was so annoying, I accidentally did it twice on different branches.