Having a Go - first time experience with Golang
robotmay.com
robotmay.com
cli_host := os.Getenv("STOMP_HOST")
if cli_host != "" {
client.Host = cli_host
}
you would be more idiomatic if you use a ; like this: if cli_host := os.Getenv("STOMP_HOST"); cli_host != "" {
client.Host = cli_host
}
But given how repetitive your setOpts is I think I might have rewritten it something like this: func getEnv(e string, d string) (r string) {
if r = os.Getenv(e); r == "" {
r = d
}
return
}
func (client *Client) setOpts() {
client.Host = getEnv("STOMP_HOST", "localhost")
client.Port = getEnv("STOMP_PORT", "62613")
client.User = getEnv("STOMP_USER", "")
client.Password = getEnv("STOMP_PASSWORD", "")
client.Uuid = getEnv("STOMP_UUID", stompngo.Uuid())
}
But then I have a thing about duplication.Have fun with Go!
Update for your update:
Aye, I wouldn't normally write so repetitively but I wasn't too sure about the best practice for things like that and I decided to just hash it out so I could play with the data. Thanks for the tips; I'm really keen to improve quickly with Go, as it's very enjoyable.
The go guys seem very dismissive of valid concerns from developers who really want to use Go:
e.g. Sarcasm for users who need to run on older linux kernels and distros: http://code.google.com/p/go/issues/detail?id=3211#c14
e.g. Solutions for 32bit memory leak is: works for me on 64bit: http://www.youtube.com/watch?v=kKQLhGZVN4A
I bought a book on Go and was planning to use it for a new project, but decided against it after seeing the disregard for developers with valid concerns who want to use the language.
2. Most of the team is a bit young and cheeky but they do mean business and actually engage the public very patiently about modifications/improvements etc in their mailing list. The dismissive attitude is usually them trying to stick to their core goals of making go an expressive, orthognal and highly readable language. Usually they have good enough reasons for picking a choice.
I would seriously recommend you to "not browse through" some source code but rather "play" with it. It really does feel different. Its like the feel of a quick dynamic language but on a more type safe static language. Its kindof fun at the least. Not the mention their CSR inspired concurrency approach. Its really interesting. Give it a shot, what you got to lose?
I'm not too concerned about the attitude of some Golang devs (they are volunteers, after all), but I am very concerned about any memory leak or other serious bug that won't be fixed for a year+.
> Sarcasm for users who need to run on older linux kernels and distros
The person Russ is sarcastically replying to is someone we know; a contributor to the project. I can see how it might look a bit blunt from the outside.
Perhaps more illuminating is Russ' later comment on the issue: "Old operating systems will always be with us. The fact that in 2020 people will be running a Linux distribution that forked the kernel 13 years earlier does not mean we have to support it." Which I feel is entirely reasonable.
> Solutions for 32bit memory leak is: works for me on 64bit
We've acknowledged the issue and work is in progress to fix it. In the meantime, however, "It works on 64-bit" is a legitimate response because it's true, and there is nothing you could do to help the programs that were affected on 32-bit systems. We never closed the issue was "works for me," we just said that's a reasonable workaround for some people.
The Go developers and wider community care a great deal about our users. We have some of the fastest bug fix turnaround of any project I've seen. We do, however, have our goals and priorities and sometimes people don't agree with them. There's not a lot you can do about that.
There are some things that annoy me.
1. Reversing type and variable/parameter name is just aesthetics I guess but it still really bothers me. Perhaps there's a reason (eg parsing speed) but I'd still prefer:
float32 f1
float32 f2 = 45.4
over var f1 float32
var f2 float32 = 45.4
2. The language is in UTF-8 so you can have snowman variable names but weirdly what gets exported from a struct or package and what doesn't is decided by uppercase/lowercase (respectively). This is a very Euro-centric concept.3. The use of braces in struct/array/slice initializers is also a little weird.
4. Probably the biggest lacking area--and I realize this is a deliberate choice--is the lack of some form of generics. I realize there are good reasons for this. If you look at Java or C#'s generics you'll see that static type checking with generics can result in some thorny edge cases.
Still, using interface{} is rather awkward and limiting and there aren't (truly) universal map, filter or reduce functions like you have in Python, Ruby, etc.
5. Still immature IDE/debugger support. I tried to set up the Go plugin on IntelliJ (my preferred IDE) but in creating a project it would fail throwing NPEs in the logs for reasons not quite clear to me.
In the end I'm using Sublime Text 2 + gocode + MarGo (for syntax completion) and it's quite nice but Sublime has some things that annoy me too (eg no "delete line" out of the box; need to add a macro). Also if you're scrolling through an auto-complete list and scroll too far up or down the list goes away and you're scrolling through the file.
That all being said, the things I like are a far longer list.
1. defer for cleanup over finally blocks (far cleaner IMHO). Minor nitpick: you do this:
f := File.Open(...)
defer f.Close()
Personally I'd prefer: defer f.Close
which is how you'd refer to functions in Python or Javascript rather than their return value, but again I guess this is a deliberate choice.2. Anonymous functions;
3. No inheritance/overloading. This may be controversial but I consider it a plus. structs can still have methods;
4. Returning multiple values. Python tuples are probably a more general (and better?) solution for this but it is nice;
5. Named return variables. Much like defer, this has the potential to really cleanup error condition/returns in functions;
6. The concurrency stuff (channels/goroutines/etc) looks nice but I'm still a novice so I'll reserve judgement.
7. Unused variables and import statements are a compiler error;
8. gofmt official style, which will hopefully kill off style dialects.
Anyway that's my experience so far (a few days in).
EDIT: I forgot my biggest beef with Go by far: the name. Seriously, try searching for "Go". Even "learning go" or "go tutorial" will bring results mixed with Go, the Japanese game. "golang" helps somewhat.
Compare this with "Clojure", which is a fantastic name in that is means something and is unambiguous in search terms.
Note to anyone naming stuff out there:
1. Don't choose any name shorter than 4 characters;
2. If it's an English word (or a word in any language), misspell it in some way.
The reason is that it is much easier to read for more complex types. eg. function pointer in C: int (*pt2Function)(float, char, char);
function pointer in Go: var pt2Function func(float32,byte,byte) int
Try writing a type that is a pointer to a function that returns a function in C. It's a bit mind bending.
Just on the editor front; I've had quite a pleasant time writing Go in vim, but I guess that depends on whether you would class using vim a pleasant time :D
[1] http://golang.org/doc/articles/gos_declaration_syntax.html
let hashmap<int,str> x;
let x;
After parsing the "let" we don't know whether to parse a type (which can be arbitrarily long) or a variable name. Switching to postfix types neatly solves the problem: let x: hashmap<int,str>;
let x;I like a lot about Rust, but one thing I vehemently dislike is how type names are all lowercase by convention. It's unambiguous in variable declarations, but everywhere else it reduces visual information. In most other languages, I immediately know that "Foo" is a type and that "foo" is a variable. Even though Rust allows for omitting the type in many places, it quickly becomes a sea of lowercase for me.
This, plus the focus on short keywords/identifiers and C++-style syntax (::, semicolons), makes Rust look a lot gnarlier than Go, overall.
It also seems to me that Rust still hasn't fully adopted its "object syntax"? One aspect of Go I really like is how functions can be used as methods and you design entire interfaces associated with a type -- the best of object-orientation without the worst. Rust also does this, but on the whole it seems the current standard library is not designed around this philosophy. For example, code uses `vec::len(foo)` instead of `foo.len()`. Are you moving away from the OO syntax, or is it simply considered a stylistic choice?
* I agree about type capitalization. I try to capitalize my types in new Rust code, and I'm advocating switching to it generally. It is currently on the roadmap. (It's not just a stylistic thing; we can fix several issues in the grammar that way, most notably the distinction between an enum like None and a variable like x.)
* The keywords are going to stay short (although some of them are being revised to read better; e.g. "cont" -> "again", "iface" -> "trait"), but identifiers are going to lengthen in new code.
* '::' may change to '.', to make it easier on the eyes. I personally prefer '.', and am advocating the change.
* You're right that Rust hasn't fully adopted dot-notation. This is an artifact of dot-notation being introduced later in the design, and we're in the process of transitioning code from vec::len(x) to x.len(). We definitely aren't moving away from the OO syntax; in fact we're moving toward traits [1] and maximally-minimal classes as a way to unify OO, Go-like interfaces, and Haskell-like typeclasses under one simple, coherent system.
I'd prefer it if semicolons stayed, however; I think automatic semicolon insertion is more trouble than it's worth, as it ruins people's house bracing styles and causes confusing errors. That said, the way a trailing semicolon changes a block's return value is very confusing, and I'm pretty sure we can fix that issue.
[1]: https://github.com/mozilla/rust/wiki/Proposal-for-unifying-t...
I'll be holding you to this promise. :) Indeed, what's the point of super-short keywords if not to allow identifiers to be more descriptive while maintaining an 80-column limit?
While I love that you are making major changes, I am sure that you are aware that the instability of the language is a problem for many people. I have been watching from the sidelines for a good while now, but aside from testing new builds and reading the developer blogs, I dare not start using Rust for anything. Niko Matsakis's recent blog entry about mutability was particularly disappointing as it seems such a basic idea should have been settled much earlier. I can appreciate the kind of experimental, agile approach to language design, of course; but while Rust is germinating, I have been forced to fall back to Go. I really hope the dust settles soon so the language can stabilize and mature.
As for the semicolons, I think a strict, well-defined rule such as the one used by Go is sufficient. Actually, Go is a bit too rigid about semicolon insertion for my taste. The following, for example, will not compile, despite the fact that the ending brace is expected by the parser:
house := &House{
color: Green,
floors: 3,
patio: true
}
On the other hand, Go is perfectly happy about: import (
"fmt"
"io"
)
...but I have not looked into why this is a special case.These design discussions would have happened behind closed doors in most other places; the fact that you can see all of it just shows how open our development process is. We deliberately haven't been making much noise about Rust because we know it's unstable. When we are ready to finalize and commit to aspects of the language design, we'll make that clear.
Mutability is pretty hard. Consider what C++ and D had to go through with const/immutable correctness. The design we came up with is pretty novel and captures all of our use cases in a simple way, but it wasn't easy to arrive at.
As an aisde, I'm curious if the core design of the language itself has been/is done online, as opposed to working closely in an office environment? In my experience, technical design is something that greatly benefits from being present in the same room as other people. The second you have to sit down and actually write out paragraphs about how you're right about some issue, and debate about it democratically with a group of people, efficiency drops significantly. I guess my hypothesis is that a small team working in a single location could bat out a language faster than a larger distributed team, and that possibly Rust has taken so long partly because it is an example of the latter.
> The design we came up with is pretty novel
Is this [1]? The roadmap makes it sound like it's up in the air ("one of the larger unknowns") at this point.
[1] http://smallcultfollowing.com/babysteps/blog/2012/05/31/muta...
So effectively "those ties mean that we cannot break completely from using parentheses to disambiguate types and expressions in the grammar".
Looks like Go's authors recognized all the issues very well and still went ahead with the final, wrong decision IMHO. They might as well have not bothered with postfix.
I knew that Go was both case-significant and Unicode-aware, but I had assumed (perhaps incorrectly) that they'd have some mechanism to export identifiers written in scripts that don't have a case distinction. Can anyone verify this? Or do they really expect e.g. Japanese programmers to write identifiers like `A緑` instead of `緑`?
EDIT: Actually, I suppose Unicode-awareness means that they'd be foisting Unicode Category Lu[1] on everyone rather than simply ASCII.
[1] http://www.fileformat.info/info/unicode/category/Lu/list.htm
Then it should not be allowed at all.
Language users will find a way though, they can just write phonetically.
How does C# handle the case of List<Sub> being used as List<IBase>?
If it is allowed, does it let you do:
List<IBase> base = subList;
base.append(someOtherSub); // Oops! Broken invariant
Is List<T> covariant on T? If not, that's a thorny edge case, which results from the combination of OO-subtyping and generics.In Haskell, I can represent the type:
(Show a, Ord a) => [a]
It seems like the same is impossible in C# due to generics' interaction with inheritance. var subs = new List<Sub>();
...
IEnumerable<Base> bases = subs;
The objects that 'subs' produces are guaranteed to be Sub's, and hence Base's, and you cannot insert a Base into 'subs' this way because IEnumerable does not have a method for doing that.More info at http://msdn.microsoft.com/en-us/library/dd799517.aspx.
It's what you'd do in pretty much every language other than Go, really. And it's quite annoying when defining the function inline: you have to remember the extraneous parens to call the function in-place.
> Python tuples are probably a more general (and better?)
Python's tuples are indeed more general, "better" is a more complex issue as the language does not provide much support for tuples management.
Erlang's tuple support is significantly better than Go's MRV-specific syntax in my opinion, so is Haskell's (although in Haskell you often would use dedicated data types where Go would use tuples, as you can pattern-match — and unpack — pretty much anything and declaring a datatype is extremely easy)
Would you really? Most of the examples I see over and over take no argument, the common case most definitely seem to be that. Not to mention it is not hard to design a HoF wrapping a callable and arguments, and deferring the application of one to the others.
> The syntax of the 'defer' keyword is obviously designed to match the syntax of the 'go' keyword for launching Goroutines
Which I consider problematic for the same issue.
> it would be annoying to wrap every 'go' call with arguments in an anonymous function without arguments.
No more annoying that calling functions being deferred, or coping with the weird irregularity of evaluating all sub-expressions but not the top-level one.
defer { result++; }
Instead of: defer func() {
result++;
}();
Also that you need such an ugly syntax just to not silently ignore return values from "defer" and "go" speaks volumes. For instance the "defer f.Close()" in the original post ignores errors from close, and with no exceptions these are just lost. It should be something more like: defer func() {
err := f.Close();
// handle error
}();
You are basically always going to use this form anyway if you care about error handling. But lack of error handling in Google Go is another issue entirely. output.WriteString("<statements>\n")
defer output.WriteString("</statements>\n")I've always found this a nice change.
The first way, you read it as: I have a float variable, named f1 and its value is 45.4.
The second way, you read it as: I have a variable named f1, it's a float, and its value is 45.4.
The second seems more natural to me, putting emphasis on your name and value, instead of the type. It is even more obvious when you use the := syntax. `f1 := 45.4` => "I have a variable named f1, whose value is 45.4 (a float)."
A graphical debugger is about the only feature you get in an IDE (at least that I use often in projects that I'd use Go for) that's missing and I'm happy enough with other debugging tools.
The C# author, Anders Hejlsberg, back when C# was around 5 years old has admitted that they failed to study the state of the art of programming language design and repeating the (very old) nullability mistake. This should despell the myth that design mistakes in modern programming languages are intentional trade-off positions. It isn't true -- modern language designers simply forsake the process of learning the various state-of-the-art languages and decide to reinvent the wheel, poorly.
People get attached to languages, so this will hurt some feelings here, but I think this is true of Go too. Rob Pike and others have repeated the mistake of failing to learn from the state of the art and re-encoded several age old PL design mistakes that could have easily been averted. A couple of clear mistakes in Go:
* Everything is nullable
* Boolean blindness
Some features that Go should have stolen:
* Sum types and pattern-matching (this would help with boolean blindness)
* Type-classes (So much more powerful than interface inheritance, and can be implemented more efficiently in many cases)
Given the majority of programmers themselves also do not study the state of the art, these designs, for all their (avoidable) mistakes become popular and persist, and make us all live with poorer-quality software for much longer.
[1] http://channel9.msdn.com/Shows/Going+Deep/Anders-Hejlsberg-Q... (1:00:35)
On the Windows platform the Zeus IDE Go language support has been constantly improving:
http://www.zeusedit.com/go.html
Jussi Jumppanen
Author: Zeus Editor