Hacker News new | past | comments | ask | show | jobs | submit login
iGo: a new Syntax for GoLang (igo.herokuapp.com)
98 points by DAddYE on March 21, 2014 | hide | past | favorite | 91 comments



I think one of the reasons for developing Go were some hard-to-find bugs with the indentation of python code. AFAIR, the Go authors specifically didn't want this.

Found it: (http://talks.golang.org/2012/splash.article)

"As a simple, self-contained example, consider the representation of program structure. Some observers objected to Go's C-like block structure with braces, preferring the use of spaces for indentation, in the style of Python or Haskell. However, we have had extensive experience tracking down build and test failures caused by cross-language builds where a Python snippet embedded in another language, for instance through a SWIG invocation, is subtly and invisibly broken by a change in the indentation of the surrounding code. Our position is therefore that, although spaces for indentation is nice for small programs, it doesn't scale well, and the bigger and more heterogeneous the code base, the more trouble it can cause. It is better to forgo convenience for safety and dependability, so Go has brace-bounded blocks. "


No. Go is beautifully straightforward and blatantly obvious as to what is going on. Don't start hiding scopes behind tabs or magically creating variables referencing structs.

Plus, with all these changes, this syntax saved 5 lines of code, most of which were simply closing braces, and brought no greater clarity. In fact, I'd argue it's probably pretty easy to mess up scope in the iGo example and never know it.


Go is beautifully straightforward and blatantly obvious as to what is going on.

I agree.

I've argued similarly on the Lua mailing list when someone wanted to change the comment characters used in the source code to be C-style instead of Lua style (double minus).

If you're going to change the language, really change it, and give enough benefit to make a break with existing code. If you are going to tweak something like comments (or in this case use significant whitespace), there isn't enough benefit (other than programmer preference) to justify the switch.

If nearly every gopher thought thought this was great and switched their code, then that's OK. But if you start using iGo, you're still going to be spending most of your time looking at regular Go source. So you need to learn the rules for Go and iGo, for negligible long term benefit.


One of the best parts of Go is that the grammar is (almost) entirely context-free - it is one of only two languages I know of in this regard - Lisp is the other[0].

This comes in handy because it is very easy to parse Go and make syntactic transformations while preserving semantic meaning. The "go fix" tool (which was used to port pre-1.0 code to Go 1.0) meant that Go never had a "py3k" moment[1]. This is not like python's "2to3" tool, which is reasonably good, but still doesn't handle every edge case.

My favorite part about writing Go is the "go fmt" tool. Because all code in the standard lib (and most third-party code by convention) is formatted using the exact same tool, it is very easy to read any Go source code I find online. I don't need to worry about stylistic differences or bikeshedding. And the "go fmt" tool exists (and is so simple to implement) in part because Go's grammar is so simple.

Go is emphatically not a Lisp (it's not even a functional language[2]). However, this one trait - the ability to make deterministic and reliable syntactic transformations - are at the core of what make Lisp's macro's powerful[3].

Like Lisp, Go's beauty lies not in the syntax but in the semantics. While I would appreciate a Go (or a Lisp) that had both more beautiful syntax and beautiful semantics, I would not want to compromise one bit on the latter.

[0] (EDIT) For the PLT nerds & pedants among us, I think mehrdada is right - in actuality, the grammar (IIRC) is fully context free, but in other languages, many of the rules which define a valid program cannot be encapsulated by the language grammar (whereas a higher proportion can). So it's less that the grammar is "(almost) entirely context-free" and more that the language is "(almost) entirely described by its grammar". That said, it has zero impact on the rest of my comment. :)

[1] Or, in the case of Python, not so much a "moment" as 5+ years and counting.

[2] It supports first-class functions, but that's about it.

[3] It does not mean that Go has macros, or even that Go can provide the same things that Lisp macros provide. It simply means that Go derives some of its power from the same place that Lisp macros derive their power.


It'd certainly be possible to have a tool -- let's say "go edit" -- which would read a set of user preferences, and apply transformations (e.g. setting spaces or tabs, variables-in-camel-case, comment-styles , etc.) to Go code. It'd be fine as long as each transformation was bijective in a way "go fmt" could revert.

Interestingly, the code existing between the "go edit" and "go fmt" steps wouldn't necessarily need to be executable as plain Go. If the Go compiler's parser+lexer shared their canonicalization logic with "go fmt", then feeding "go edit"-munged Go to the compiler would implicitly re-canonicalize it before compiling it. So you could have transformations involving things like significant whitespace.

In fact, the pair of filters "go edit" and "go fmt" could even be made into a read/write filter-pair for a FUSE filesystem: in effect, the code on-disk would always be represented in the canonical "go fmt"ed manner, while the code you'd see in your editor would always be in your own personal "go edit" style.

And then, 56 years after McCarthy's LISP, we'd finally have our M-expressions. ;)

(And the serialized representation could finally be stored as a binary AST tree, and we could embrace visual-symbolic hybrid languages, and entertain divergent syntaxes with unified AST-level semantics, and have one universal runtime library, and...)


This is mostly the aim of this project.


> One of the best parts of Go is that the grammar is (almost) entirely context-free

You mean almost regular. Almost all programming language grammars are context-free. Regularity is a much higher bar to reach.


> Almost all programming language grammars are context-free.

Er no, almost no programming language grammar is actually context-free (in the sense that they can be parsed unambiguously according to a context-free grammar)


Unambiguous parsing is not a requirement for a language to be context-free. Your use of "actually context-free" is a stretch of the definition by a huge margin. In fact, the definition of a context-free language does not depend on a specific grammar at all. You can have a context-free grammar that parses a language unambiguously and another grammar that ambiguously defines the same language.

It is true, however, that most formal grammars for programming languages define a strict superset of the actual language and then restrict it according to semantic rules (e.g. type checking, definite assignment rules). That is why in my original comment, I was careful to use the phrase "programming language grammars", instead of "programming languages".


Pretty sure he means 'almost' context free (as opposed to 'very' context sensitive. C is context sensitive. A language like C++ is heavily context sensitive (actually, C++'s templates make it recursively enumerable iirc, so even worse..)).

Being regular would mean that you could decide it with regular expressions. Regular expressions are insufficiently powerful for matched parentheses of arbitrary depth, which is a good hint that Lisp and Go are not regular (or 'near' regular).


> Being regular would mean that you could decide it with regular expressions.

Hence almost regular. Of course, there is no concrete definition for "almost regular", but what I mean by it (Rob Pike himself also characterizes it as such too[1]), is that you get to decide which way to parse a construct quite definitely early in the token stream and you don't have to read arbitrary following tokens to figure out how to construct a parse tree branch.

C++ is the exception here. Most other block oriented high level programming language (at the syntax level) are indeed fully context-free, so just being context-free does not deserve a high prize.

[1]: http://www.infoq.com/presentations/Go-Google


Do you have the timestamp of when in this talk Rob Pike mentions this? If he says that it is "almost regular", then that settles it in my book, but I am pretty certain that you are wrong about most block oriented high level languages being context free.

C++ is an extreme case, as it's Turing complete, but C is definitely context sensitive (http://eli.thegreenplace.net/2007/11/24/the-context-sensitiv...), Perl is just as bad as C++ (http://www.perlmonks.org/?node_id=663393), and I can't find a link for it right now but IIRC the Java is context sensitive for some reason too.


In that video mentions regularity around minute 51. I have seen him using that term in person too.

The blog post you mentioned is misinformed. YACC does not parse all context-free grammars. It generates LALR parsers, that parse a strict subset of context-free languages (called deterministic context free languages). Not parseable with YACC does not imply not context free.

It is important to distinguish the programming language and its syntax. In most real compilers, the parser accepts a superset of the programming language and then other components of the compiler restrict it with semantic rules like type checking. What I am talking about here is the syntax only. In that sense, things like C, Java, and C# are most definitely context-free. The language specification usually comes with a context-free grammar describing the syntax. Whether you can use it to parse programs efficiently (in O(n)) and meaningfully is another matter.


If a piece of C code that parses in two different ways, depending on what other code may have also been parsed, isn't context sensitive, then what is?



You are meaning that it is an LL(k) parser. Rust is an example of an LL(1) parser. Various things that might be convenient to have in the language in certain circumstances have been rejected because they would cause ambiguity in the parser which would require arbitrary lookahead.

https://en.wikipedia.org/wiki/LL_parser


What I have in mind is more loosely defined than LL(k) and in a way more restrictive than a general LL(k) grammar, but LL(k) is probably a good way to formally capture something close to what I had in mind. I try to avoid using the term "almost regular" as it is imprecise. I only used it since it was relevant to the context and I'd heard Rob Pike describe Go as having almost regular syntax several times.


> One of the best parts of Go is that the grammar is (almost) entirely context-free

If the threshold is almost-context-free there's a host of matching languages: C (IIRC it's context-free if you remove typedefs), Rust, Pascal and descendants (Oberon), Python, java, …

If the threshold is actual context-freedom, I don't recall anything outside lisps.


You can still make syntactic transformations in the same way you would for any other language: use an AST. No syntax compromise required.


> One of the best parts of Go is that the grammar is (almost) entirely context-free - it is one of only two languages I know of in this regard[0]

There is also Erlang [1] and my personal rethought version [2] featuring no ,.; and more…

[1] https://github.com/erlang/otp/blob/maint/lib/stdlib/src/erl_...

[2] https://github.com/fenollp/kju


Go should be in an excellent position to have Refactoring Editors. Smalltalk had a Refactoring Browser that worked well enough that it changed the economics/trade offs around refactoring. (Literally an order of magnitude easier refactoring combined with immediate/really fast responsiveness.)

Such tools, positioned such that they are defacto standards can cause qualitative changes in how programming happens in a language.


The isomorphism between the sources could be tweaked. For instance, around line 26 on the iGo side, there's a newline that doesn't appear on the other side, and the closing brace is right next to func main. On line 48 in iGo, note the comment ends up after the braces of something that should have already been closed out. In general, braces seem to end up with an extra line on the end too often.

I do not like the do syntax; for a very dubious improvement in syntax, you turn an N-parameter function into an N-1 parameter function visually. This is a net loss. (Go is not curried.) It's not even a huge character win, given that you've already disposed of the braces. I'm not convinced those stack very composably either, though I'll admit I'm not taking the time to prove that.

In fact, in general be wary of that issue in syntax, real code will encounter all the corner cases that can possibly exist as the elements are composed together. Can I call a

   func (string, func(string, func(bool) bool) string)
with your do syntax being used twice? If not, or if it's not easy, that's a bad sign. Vanilla Go I can type that correctly the first time... it may be a lot of braces but it's unambiguous. It may be wise to avoid trying to sugar function applications like that, if you can possibly avoid it.


Why sacrifice consistency for some minor syntax changes?

We have gofmt so that everyone's code looks the same, and now this? I don't see the benefit.


I can write code in iGo and save it as .go. You'll never know if the code was written using Go syntax or iGo syntax, whether the person used tabs of width 4, 8, or 2 (it'll be a '\t' character in the file), or if they used Sublime Text or vim or emacs.


Oh really? So the igo code won't be checked into your repo? The comments you've made will be preserved and in the right place in the resulting code? And you'll be writing go code that other go programmers will find idiomatic and easy to read?

Also, if you use igo won't you have to adjust to read other peoples non-igo code? Or will you use a converter tool whenever you read any go code?


Yes, that's the idea. The current implementation may not be finished/perfect.

> Also, if you use igo won't you have to adjust to read other peoples non-igo code? Or will you use a converter tool whenever you read any go code?

"Converter tool" makes it sound like you find it unreasonable. Do people use "converter tools" to view .html files in a rendered format? No, they use a browser. Or to display '\t' characters with different widths? Use a text editor: http://img534.imageshack.us/img534/1627/zo3w.png

If you're gonna write Go code using iGo syntax, you're probably going to be using a code editor that supports iGo (I don't think one exists yet, this is just a prototype).

You're not gonna be converting from .go to .igo manually, that'd be like running gofmt manually. I don't run gofmt manually, it happens on save (and in fact, I use goimports instead of gofmt).


The converter tool comment was in the context of reading code on GitHub, for example.


I believe his point is that iGo is just a way of editing .go files. It's not as though you would be saving .igo files to disk or anything. So, it's totally unrelated to any kind of version control or file management, much less to Github.


No, it's not. Because if you're used to reading igo code and then you're browsing normal Go code in GitHub or watching a talk or reading a tutorial, you're going to have to mentally translate that code to igo. It's needless mental acrobatics.


Most presentations don't use pure go-fmt'd code, they usually do some vertical space compression to get the code to fit on the slides better. So technically you already have to do this anyways.


Don't forget about godoc.



It seems like a real "because we can" thing. Coffee script is smelly in the same way.


Um no. Apart from being pretty coffee-script makes you stick with good object definition conventions, hides away unsafe comparisons (== vs ===), and is generally much more easily understood. This is one of coffeescript's main focus points : hide away the not so nice features of js, and highlight the good parts.


Yeah, but the language is what it is. It's out there, it's in all the browsers, it's not going away.

Rather than just learn to idiomatically write code that uses the nice features of js while avoiding the bad parts; we have two totally different notations to learn. That only causes further fragmentation.


I am usually wary of new languages, because they come at a great cost. All the code I've written, libraries I've discovered, standard library I'm used to and take for granted are suddenly gone, and I have to start from scratch. On the plus side, the new language may have desirable aspects that are improved.

However, this is not that. Despite looking like a different language, in reality, it's just a different _interface_ to writing/reading Go. It's completely compatible with all the libraries, tools that work on Go code because it _is_ Go code, simply expressed via a different representation of the Go AST.

I think that is a really nice way to experiment with the positive aspects of new languages/syntaxes. Nicely done!


http://en.wikipedia.org/wiki/Bidirectional_transformation

It might be interesting to hook up different AST representations directly into an editor, in this case iGo would never exist on disk. Really all he has done is push what would be an editor completion into a new sytnax.


I really respect the way this was posted. A simple side by side. Most of the times stuff like this is posted, it is a horrifically convoluted example to try to show the massive code savings, this one is just -- honest. You save a few lines of code.

That all said, the syntax is godawful. It brings back so many horrors from Python, whitespace, self, ugh. The next step to make it truly awful would be have those minor whitespace errors only show themselves at runtime so writing complex applications becomes a nightmare.

Love the attitude, abhor the project.


It's hilarious to see someone add semantic whitespace to Go, which seems to be the opposite of Python With Braces[0].

I'm in the whitespace > braces camp, but mandatory braces help with the dangling else problem and makes it easier for the parser.

[0] http://www.pythonb.org/


I'm unfamiliar with this dangling else problem. I googled it and I don't see how it could be a problem with significant whitespace.

I can understand making it faster for the parser, though.


You've ruined a syntax designed to fix a lot of common syntax errors by replacing all that work with Python syntax.

Gross.


Why is significant-whitespace vs. braces a significant issue for people? I've coded in both and while I suppose I would have to say that I'm "most" comfortable with braces, I don't find SW that different.

The semantics of the code haven't changed at all. It's not like we're going from C to O'Caml here. This doesn't enable a different way of thinking about the code.

I guess I just feel that, if I could run a set of very simple regexes over Code A to get Code B, then I haven't really gained anything [1]. Maybe that's a sign of the times. Maybe we live in an era in which the various programming languages have evolved to share so many features that a trivial translation exists for the majority of scenarios.

Perhaps I'm over-thinking it. Maybe OP was proud of his/her presentation. It's pretty neat, how the two halves of the screen are presented.

[1] an opinion born from having spent time running simple regexes over Code A to get Code B and realizing I hadn't really gotten anything out of it.


Personally, it's not a significant issue, but it is a preference. Do you indent code when coding with braces? How anal are you about keeping your code formatted consistently (i.e. spaces after operators)?


Sometimes, not always. I'm likely to put a one-line getter/setter on one line.

I use formatter tools to do most of the formatting. It's nice to have formatted code, but I'm not fastidious about it. It's bound to Ctrl+K, Ctrl+D in Visual Studio. I prefix it to Ctrl+S out of habit. But if the automatic formatter can't take care of it, I don't bother changing anything. Simplicity and consistency are more important than "having my way".

Code should be readable, which is a human issue. As such, I think it's always going to have edge cases where "breaking the rules" is appropriate.

EDIT: Come to think of it, I often use the formatting as a pre-check before compiling. If the formatter doesn't format the code as I expect it to, it means I've screwed up a block somewhere. That's pretty much it for me.


This is 100% a non-issue in go. gofmt will automatically make all of your code look just like how everyone else writes it.

In addition most editors have plugins for automatic gofmt on save.


I dig the syntax on receivers, and the short body declaration syntax. the whitespace—meh. I'm less offended than i used to be by whitespace languages like python, but i've also been bitten many times by incorrect indentation that took me a few minutes to track down. annoying, but not catastrophic, and certainly more readable.

My biggest concern in using it would be that its a tool that saves me some keystrokes (perhaps not insubstantial advantage—i'm tired enough of faking partial application in JS that I'm almost ready to start using coffeescript if only for the -> operator) but it doesn't really offer many other advantages, and will probably complicate my life at some point (i.e. i'm grumpy and suspicious of new things. shrug)

Even so, looks fun, and options are good. nice work—hope it gets some traction and evolves.


The most obvious advantage here is that the code at the left is much more concise. This is good because then more code will fit in the same screen.

Not sure this is what Go needs though.


> Not sure this is what Go needs though.

Yep, a generics prototype would be better spent time.


I was actually going to include that in my comment. Go really needs generics.


How is more code on the same screen a good thing?


A lot of programmers seem to think that (the more code they can jam on the screen at a time the better, and thus any unnecessary newlines are superfluous), but I also don't understand why many are so rabid about it.

We generally don't code on 80x25 character terminals anymore, super high res monitors are cheap, vertical lines in code aren't a scarce commodity.

Personally I tend to like a fair amount of vertical whitespace (either in pure whitespace form or comments) in my code to split things up logically, even within the same function and when the newlines aren't required, eg:

  x = 10
  y = 20
  z = 0

  speed = 80
Variables assignments/func calls, etc that are closely coupled kept together, but some whitespace as things become less directly linked. I'd rather be able to quickly scan code in 10-40 line chunks than fit more code on the screen at once.


Many things are valuable. Conciseness per se is valuable (I don't think you will argue in favor of unnecessary verbosity in programming). However, of course this is just one of many factors, and any programming language will have to find a balance between these many factors, depending on how important each is, and so on.

If you think you are getting conciseness by decreasing readability then you probably have a balancing issue, but if you can get more concise code without decreasing readability then that's good news.


I comically interpreted your example of hi-res monitors as jamming more code on the screen at once.


2 lines is certainly better than 1 line. 10 better than 2. I don't know where it tops out, if ever.

100 chars/line better than 200. 60 better than 100. I don't know where it bottoms out.

That's how it's a good thing (not sure if you were being serious).


Less scorlling?

On the other hand many young developers these days seem to think, that scrolling is good and insert lots of blank lines everywhere.


So what's the intended workflow here? You write your code in IGo syntax. Now, you can't compile that code until it's been converted to real Go.

And you need to commit the Go source, not just the IGo source, because other people don't want to see your Python-esque Go.

And once you compile your code, now any error messages are going to have the wrong line number associated with them if you look at the IGo source. So when it comes time to debug, I guess you have to switch to reading the auto-generated Go and making changes in your IGo from there.

This seems like an awful lot of hassle in order to achieve what is arguably the worst part of Python syntax: significant whitespace.


You should call this CoffeeGo, because it's basically what CoffeeScript did to JavaScript.


Hi all,

I'd like to explain one thing, right now the `go build` etc... isn't implemented.

There is a good reason for that.

You may not want to distribute `igo` files, this `syntax` should work in the very same way of `go fmt`.

The idea is allowing you to write as you like (for me indenting) then distribute your files as you always did with `go fmt`, so the `code` will be always `.go` files formatted in the standard way, with comments as well.

That's it.

Cheers, DD


The experiment's upvote-worthy and I applaud the effort, but there's no chance I'll ever use this personally. In practice, I don't think I've ever been annoyed by the syntax of Go. Perhaps the one iffy behaviour has been the way multi-valued := wriggles around mixed declaration/assignment dependant on what's already in scope.


For some reason I find this less readable than the original syntax. I couldn't say why, as I quite like Python or Coffeescript.


I'd agree. I think the biggest thing for me is that I had to think about what was being expressed on the left hand side while the right hand side seems more explicit and straight forward. Provided that and the fact that only a handful of lines were actually saved, I don't see much advantage.


I can't say that I find it less readable... but it is only marginally better for me. I'd rather just use a decent editor which takes care of the braces for me.


I'd agree. Python developer myself and I think the missing colons might be an issue here.


What is so wrong with curly braces?


They are annoying to type.


Maybe it is because I've been programming in for something like 24 years, but I don't find them annoying to type at all; Also, maybe I'm just slow, but my typing speed is hardly the bottleneck for me in writing code; I doubt it would be even if I typed at like 20 wpm (about 95 wpm for me, and I don't touchtype). And then lastly, you can always remap your keyboard to make {} non-shift characters and/or use a language parsing IDE/editor that auto-inserts braces.


They are really annoying on non US keyboards.

The common user don't really uses them, therefore they aren't even mapped in eu keyboards. Clearly the solution is to change the mapping, but as you can imagine, many people still need to look at the keyboard when typing... So how do you fix that?

I can teach my wife to code python, but if she has to type alt-gr 123 for every curly brace in JS, she will be tired quite soon.


{}{}{{{{}}}}} typing those didn't annoy me at all


IGo as-is could've been just an alternate colored-syntax mode with color of curly characters set to background color. Much less work with same result.


I don't think that's a fair statement. You would still have to keep track of and type curly braces, only now they'd be invisible.


I would agree if not having to type curly characters is a major benefit of IGo syntax. As a CoffeeScript user, primary benefit of IGo I see is in readability, not saving keystrokes which I think TextMate/Sublime Text macros are better at.


They almost went to python but then added weird inconsistencies with how colon works. Why is it omitted in the else clause? Why isn't it used in all blocks like with python?


This is not about 'New' Syntax. Use eclipse or vim plugin to generate the template for you is better. So you never type ‘}’ again


I kinda want to see Rust without braces or semicolons, although I'm not sure what you'd do with implicit return.


Nimrod solved that... The solution in a nutshell: If a statement list contains a 'return', it enforces a 'void' context for the statement list, otherwise the statement list has the type of the tailing expression e in (s; s; e).


Why isn't this pre-populated with examples that demonstrate the advantages of IGo?

EDIT: Oh, weird. After refreshing I now see it.


Yep, sorry I'm unable to find/reproduce this bug with ace editor.


Had the same problem.

Using: Chrome Version 33.0.1750.152 Have Adblock installed.


same thing happened to me, except I saw the first two lines of the example. weird.


I appreciate the inline if-else statements. I'm so tired of having:

if err != nil { return err }

Take up 70% of all lines in a function.


the cost in making the code harder to parse (both for compilers and, IMO, humans) isn't worth it. Using short assignment mixed with if makes the Go error handling branch code not so bad, eg instead of:

  err = doSomething

  if err != nil {
    return err
  }
do:

  if err = doSomething(); err != nil {
    return err
  }
Also if your function only returns err, I'd use a named return to save even more typing. I know they are seen as a bit of a red-headed stepchild by much of the Go community these days, but I still like them if used carefully:

  func whatever() (err error) {
    if err = doSomething(); err != nil {
       return
    }

    ...

  }


That definitely helps, though you can't use it to introduce new variables with the := syntax:

if buf, err := json.Marshal(make(chan int)); err != nil { fmt.Println("Ehh..", err) return }

In this case, buf will not be available outside of the if statement. Go fmt can already leave your insignificant whitespace as is, I just wish it could also leave the if error != nil statement say in one line instead of formatting it to take three.


If all you want is the vspace savings, you could easily make this happen as an editor mode.


The IGo syntax looks very similar to F# with significant whitespace.


As an F# and Go developer, I reckon you should say, "IGo syntax looks very familiar to [any language which uses significant whitespace]". However, I'd still disagree with that statement.


People who are willing to reinvent the syntax of a language only to shave a few parens and braces have a lot to learn yet about what truly matters.


Agreed. I spent a lot of time worrying about syntax in my first year or two of programming. Then, I gradually opened my mind and discovered a whole world of amazing languages with syntax I had found distasteful and previously avoided.


Useless


You created and ID just to say that?


He's right, though.


It's an opinion, so just stating "useless" and moving on doesn't actually help in any way. Describing why he thinks it's useless, or upvoting comments that he agrees with, might actually help.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: