#2138 Fantom block syntax: proposal to reduce visible cruft

tomcl Sun 28 Apr 2013

Since Fantom cleans up so many things in Java I don't like I was wondering about block delimiters.

Provided there is suitable tool support (and who would program nowadays without decent tool support) Python-like block syntax with delimiters inferred from indentation has the big advantage that more of the program can be seen on one screen, at no cost to readability. After a very short initial period of weirdness it is much more efficient.

So: could Fantom do something about this to clean up syntax?

One option, and I'm surprised not to have seen this discussed elsewhere, would be an editor that folded lines containing only a brace replacing them with indentation, and inserted braces from indentation automatically, in the saved source.

That would eliminate the one disadvantage of white space determining block structure, which is problems with tabs and incompatibility between different editors.

This feature could be an optional view in the editor, so those who cannot read code without extra braces can keep them.

Braces used with other text on a single line (closures etc)could still be used, giving the best of both worlds.

Does anyone know of tools already doing this? I'm interested, it seems so obvious that to {} or not should be a property of code view in an editor rather than of the base language, and that the transformation is easily systematised. For more compact languages like Fantom it becomes more advantageous to get rid of the unnecessary {} when editing or writing code, though you also want to allow them for comfort in people used to using them.

For example: the following random Fantom example code with reduce screen vertical space by 36% elimimating {}s at no loss to readability.

Void batchSend()
{
  "// open a session, send multiple emails, and guarantee close"
  mailer := makeClient
  mailer.open
  try
  {
    3.times |i|
    {
      email := Email
      {
        to=[testTo]
        from=testFrom
        subject="Batch #$i"
        body=TextPart { text = "Batch body #i" }
      }
      mailer.send(email)
    }
  }
  finally mailer.close
}



Void batchSend()
  "// open a session, send multiple emails, and guarantee close"
  mailer := makeClient
  mailer.open
  try
    3.times |i|
      email := Email
        to=[testTo]
        from=testFrom
        subject="Batch #$i"
        body=TextPart { text = "Batch body #i" }
      mailer.send(email)
  finally mailer.close

brian Fri 3 May 2013

I might like options like that in text editor, but I am not a fan of that approach in source code text.

tomcl Mon 6 May 2013

Thanks Brian, I can see why looking more closely at Fantom, and my point was indeed that some syntactic issues should be the province of the editor.

I'm keeping my not very informed (new to Fantom) comments to this one thread.

I'm overall very impressed with the language decisions made in Fantom.

Also with the quality of the documentation.

Reading the language spec for the first time it was all very nicely laid out and easy to understand, but one exception is worth noting:

  • With-block collections (itAdd syntax) are used as syntactic sugar for FWT stuff and I guess many other things.
  • They certainly make FWT code much more readable. I noted them there.
  • It took me 20 minutes reading the language spec to find their definition, noting first the syntax from some FWT examples! I reckoned immediately that they were probably something relating to it-blocks, but the collection syntax is very well hidden under "serialisation". Because of the three syntactic shortcuts: omission of with(), omission of closure signature, and omission of add(), this syntax is remarkably obscure to somone looking at language for the first time!
  • The way I found it in the end was checking the BNF grammar and then global searching all documentation for itAdd!
  • So perhaps a small addition to the closure documentation mentioning collections would be merited?

I'm also fascinated by the discussions of strong typing and generics on here. Just one comment. Richer type systems (e.g. Scala) are used as way to document partial program specifications and also, if type-checking is algorithmically tractable, to provide static error checking of programs against (type) specifications.

These two different motivations have become identified. But they are not identical. So you might allow a richer type system for documentation of intent which cannot always be statically checked, but will provide (automatically) dynamic safety even so. It could then be used where appropriate (documenting reusuable code) without permeating the entire language.

The minus of this is that you lose static guarantees. The positive that you have more flexibility in what your type system is. Also, though static guarantees are lost, useful static checking of common cases through type inference may still be possible.

Maybe something along these lines could make a solution to the generics problem consistent with the Fantom language style? Or maybe I'm not seeing the matter clearly.

Best wishes, Tom

brian Mon 6 May 2013

Thanks for feedback. I pushed a change to beef up docs for with-blocks and comma operator. You are right there was not a very good explanation of that.

KevinKelley Tue 7 May 2013

Quick glance at your changeset...

// this long-hand syntax
pane.with
{
  add(child1)
  add(child2)
  add(child3)
}

// can be collapsed to this with-block and comma operator
pane
{
  child1,
  child2,
  child3
}

...shouldn't there be a comma after child3? --this one seems to be a common gotcha that requires a special "brain-check"; semicolons are seldom significant, but commas here are.

iateyourtoothpaste Tue 7 May 2013

No. I don't believe there should be a last comma - ever.

Having a comma indicates that there is more to come. If anything, there should be a period after child3 - but I don't see that ever happening.

brian Tue 7 May 2013

The comma is only significant in the special case of one item:

fansh> Obj[,] { 1, 2, 3 }
[1, 2, 3]
fansh> Obj[,] { 1, 2, 3, }
[1, 2, 3]
fansh> Obj[,] { 1, }
[1]

KevinKelley Tue 7 May 2013

...but there's a lot of fwt stuff that looks like this -- from the docLang::Expressions#collections docs:

Menu
{
  text = "File"
  MenuItem { text = "Open"; onAction.add { echo("open") } },
  MenuItem { text = "Save"; onAction.add { echo("save") } },
}

where you've got arbitrary other code interspersed with the elements being added.

Is that final comma (after the second menuitem) required, optional, or just confusing?

brian Tue 7 May 2013

It is optional, but by convention I like it (I even do that in my lists and maps to make it easy to go back and add new items)

KevinKelley Tue 7 May 2013

I agree with what you're saying, but not sure the compiler does... for example if I take off the trailing comma in the fwt-hello example:

using gfx
using fwt

**
** FwtHello is as simple as it gets
**
class FwtHello
{
  Void main()
  {
    Window
    {
      size = Size(300,200)
      Label { text = "Hello world"; halign=Halign.center }
    }.open
  }
}

I get

S:\comma.fan(14,13): Not a statement
ERROR: cannot compile script

KevinKelley Tue 7 May 2013

...but if I do

Label { text = "Hello world"; halign=Halign.center },
Label { text = "Hello world"; halign=Halign.center }

then it works.

Maybe the comma's like the semicolon and only occasionally necessary for disambiguation.

edit sorry, I realize that's your "only necessary for single-item add" exception.

Login or Signup to reply.