iGo: a new Syntax for GoLang
igo.herokuapp.com
igo.herokuapp.com
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. "
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.
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.
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.
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_...
You mean almost regular. Almost all programming language grammars are context-free. Regularity is a much higher bar to reach.
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).
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.
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.
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.
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)
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".
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...)
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.
Such tools, positioned such that they are defacto standards can cause qualitative changes in how programming happens in a language.
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.We have gofmt so that everyone's code looks the same, and now this? I don't see the benefit.
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?
> 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).
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.
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!
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.
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.
I'm in the whitespace > braces camp, but mandatory braces help with the dangling else problem and makes it easier for the parser.
I can understand making it faster for the parser, though.
Gross.
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.
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.
In addition most editors have plugins for automatic gofmt on save.
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.
Not sure this is what Go needs though.
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.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.
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).
On the other hand many young developers these days seem to think, that scrolling is good and insert lots of blank lines everywhere.
Yep, a generics prototype would be better spent time.
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.
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 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.
EDIT: Oh, weird. After refreshing I now see it.
Using: Chrome Version 33.0.1750.152 Have Adblock installed.
if err != nil { return err }
Take up 70% of all lines in a function.
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
}
...
}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.