Leaving Go
jozefg.bitbucket.org
jozefg.bitbucket.org
Here's the thing: I am willing to accept that Haskell is the best programming language ever created. People have been telling me this for over 15 years now. And yet it seems like the most complex code written in Haskell is the Haskell compiler itself (and maybe some tooling around it). If Haskell's clear advantages really make that much of a difference, maybe its (very vocal) supporters should start doing really impressive things with it rather than write compilers. I don't know, write a really safe operating system; a novel database; some crazy Watson-like machine; a never-failing hardware controller. Otherwise, all of this is just talk.
On the other hand, these dialects are embedded DSLs; specialized languages created and hosted by a base language. People seem to balk less at the idea of DSLs compared to the idea of powerful languages.
Take Clojure for example. A lot of people including myself like this language a lot, but to be productive in it, you have to get used to the JVM, Lisp s-expressions, a heavily functional programming style with few side effects, a significant break from a normal approach to OOP, and Clojure's distinctive concurrency constructs which are more complex than Go's. It's not that any one of these things is hard, but you have to know all of them. Unless you have Lisp, or Haskell (or similar) experience, the only one you're likely to know is the JVM, and even then, maybe not.
This isn't like C++ or Java which are huge languages with a lot to wrap your head around but at core simply reuse concepts that most programmers are familiar with, (OOP, basic types) It's the very things that make the language interesting to begin with that makes it trickier to pick up.
Most of this holds for Haskell, Erlang, etc.
Then again, real code is written in these languages, but they don't tend to dominate.
I've written Haskell, I've written Scheme, I picked up Go in a couple weeks, and learning a new functional language shouldn't take me more a few weeks. Nevertheless, if I were starting a project now, I would probably pick some combination of Python/Java/C++. Why? Because their library support & ecosystem far outweighs any productivity boosts I could get with Go, Node.js, Clojure, Erlang, Haskell, etc. And yeah, I know you can use Java classes with Scala/Clojure, but there's an impedance mismatch mapping the concepts and existing library structure onto a functional language that doesn't exist with Jython.
Wikipedia claims that there are over 200 billion (with a 'B') lines of COBOL in production. That further supports your point, of course.
I'm not sure what the cause is, but it definitely gnaws at me.
Yes, and that says a lot about the final quality too, no? We could say the same about Perl/PHP/Java/C++ and then we're sitting in the same horrible morass we live in today, because people settle for minimally bad code produced as fast as possible.
Good, cheap, fast. Pick 2. Almost invariably: Cheap+fast are the picked results.
But you see, this is the claim that requires substantial evidence. Let's assume we're in a mess. If Haskell is one way out of it, as some people claim, why won't they show us the way? They've had more than 20 years to do it. There are enough Haskell developers out there to give us this pesky evidence we need. And yet we've seen absolutely none. There are way more impressive BASIC programs out there than Haskell programs. I think that there are two reasons for that: 1) People involved in PL research are less interested in programs that aren't compilers, and 2) languages like Haskell make certain tradeoffs that their designers fail to see, and as a result their advantages fall way short of the claims they make.
My internet is filled with half-baked webapps with bad errors and riddled with stupid security vulnerabilities, many of which can be defined to not occur in an adequately designed tech stack. Desktop programs work through dint of manpower, crufty testing environments, and users-as-QA.
What exactly are you looking for? Web app frameworks? they exist. database connectors? they exist. mathematical proofs relating to correctness? they exist, in abundance. data structures arcane and common? they exist. regex libs? they exist. Sophisticated programs running sophisticated systems? They exist, and you won't hear about them except as a rumor on message boards...
If you mean, "is there going to be a big marketing campaign to make me and my manager feel comfortable"... I doubt it.
Not really. Well, far less than in all those horrible, unusable languages. All I'm saying is, if Haskell makes writing correct code so easy, where is it? There should be tons of it now. It should be practically everywhere. In fact, it should be financially stupid to do anything in any language other than Haskell. So where are all the companies making a fortune by betting on Haskell?
The reality is that most companies choose "fast+cheap" and usually incur significant technical debt which is paid off through throwing bodies at the problem. It is usually considered better to hire 3 people who are mediocre than 1 person who is very skilled. This is extremely well addressed in the software engineering literature going back to the late 60s.
It's also the case that software engineering is very conservative: "Don't change ANYTHING" is the default state of the industry with regards to practices.
Where is the redis of Haskell? The ffmpeg of ML? There's something else at play here.
e.g., I run a tutorial site for common lisp. One request has been for 'example of web framework'. At some point, I'll do it (it's useful), but my heart at the moment is in implementing an extensible indexing system for n-dimensional tuples. It's a good deal more esoteric and a lot more fun than screwing with http/html.
I'm not willing to claim that Haskell is perfect, but I am willing to claim it is better. I'm also willing to claim that if it had anything resembling the community, say, C# has (to pick a random example) then it'd solve most of the problems you're highlighting here.
And it's getting that way. The number of programmers proficient in it and projects succeeding using it grow year over year.
But if you want to argue from a perfect world then you need to note reality will look different and search for trajectories that aim to approach your perfect world... not just current states which are far from it.
Absolutely. Which means that there are substantial switching cost, which a slight marginal improvement can't overcome. But if benefits are so immense, they should be able to. I think Haskell's supporters tend to overstate its advantages (and it certainly has plenty of those), and discount its disadvantages (and it's got plenty of those, too). All in all, Haskell is an extremely interesting and very good language, but it most certainly does not solve all or even most of the challenges of modern software development. It's good, it's very interesting, but it's not the second coming. I, for one, would take the JVMs monitoring and hot code swapping capabilities over Haskell's type safety, because those solve a bigger pain point for me.
Ultimately, choose the tools with tradeoffs beneficial to your goals, obviously. Engineering of any kind is nothing if not about understanding tradeoffs.
That all said, I do think there are upgrade paths for both technologies—JVM languages with better semantics and "ML-alike" implementations with better runtimes. I'd be more than happy to use either.
And this is why better languages fail: because language weenies have atypical minds, and can't comprehend why something marketed inappropriately to the mainstream never catches on as something mainstream.
This is also precisely why Java succeeded. This is also why LightTable finally got across what Smalltalkers had been raving about. It's really not only about who has the best tech or the best message. It's who has the best tech that can make itself understood.
- Elm's Time Travelling Debugger: http://debug.elm-lang.org/
- Pandoc: https://github.com/jgm/pandoc
- XMonad: http://xmonad.org/
- (GHC, should really count)
Haskell seems to disseminate ideas rather than code. It even disseminated LINQ into C#.
Perhaps this makes the lack of volume of production Haskell code less stinging because it has contributed to languages in other ways?
There's kind of an upside to this as well, because Haskell isn't entrenched in industry, it's still free to make changes and grow the language (i.e. Applicative becomes superclass of Monad), although this gap may be starting to slowly close with the recent popularity.
Stuff that people are willing to pay for, which can be a very important concept for many (if not most) of us.
My theory is that it is because that is what we teach. If you go to school you learn Java (which is basically C#) and if you learn a language on your own most people recommend Java/C# because it will get you a job.
By extension we end up with the vast majority of coders knowing Java/C#, thus most code gets written that way.
Asking someone to switch to using a new paradigm—like moving from OOP to FP—is asking them to relearn how to structure a program. All those habits and instincts no longer apply and new ones need to be learned. It takes years to learn how to write good high-quality FP programs. I know I'm still learning and I first picked up Haskell as a primary hobby four years ago. It probably took me a year before I really understood what a monad was and could apply that abstraction, similar to how long it took me to really understand and apply things like visitor patterns.
I believe that if you took an entirely untrained person you could get them to be at least as productive if you taught them with FP versus OOP from the start.
Here's my hypothesis: programming language are made for people to use, and people spending time thinking about designing Watson, don't want to spend it thinking about expressing their program using lambda calculus. The only group for whom the stuff they develop coincides with language concepts are those writing compilers. So they get confused because their domain is the programming language, so they don't feel like they're spending their mind power on two different things. They can't imagine that someone trying to solve a tricky scheduling problem wouldn't want to spend time thinking about types.
The other group that can adopt languages like Haskell are those whose domain doesn't require too much thought: namely CRUD applications. These guys want to spend time thinking about type-driven-design. It might actually make their code quality better. They, too, can't understand why people solving a hard concurrent-data-structure problem wouldn't want to spend time thinking about expressing their ideas elegantly through types.
Both of these groups have one thing in common: expendable energy to spend thinking about programming language concepts. So to them, it seems easy; and it probably is, if you're willing to put some effort into it, which is precisely what many developers don't want to do.
Maybe. Then again, I've been using C++ again recently and I feel like the cognitive overhead there is so huge that I can barely understand my simple programs. Nonetheless, Microsoft pretty much runs on C++ (and C#).
Sometimes, I get so frustrated by how weird the syntax can get (the templates always confuse me to the point I have to stop and slowly read the code before I get its meaning)!
Elisp gurus, in my experience, don't get all that much work done, other than writing lots of editor extensions. This is great if their job is writing editor extensions, less great if their job is something else. It's the same as with compiler writers: they're great at making other people more productive, but when it comes to writing end-user software, not so much. In general, of course - there are exceptions.
I find Ruby, C[0] and Go really fun. The reason I get shit done is because they are so fun! I can't wait to do something else in them!
Also, the elegant utility library code that took four hours to write can—and likely will—be reused, and save you hours upon hours.
Meanwhile, the Java hacker will always have +1 hour of coding, because he never learns.
[0]: I realise calling C fun is weird, but I enjoy writing C code, and it's my guilty pleasure, I guess.
It basically allows you to procedurally generate thumping dance music by live coding in a Haskell DSL in Emacs.
Which, given Haskell's rather academic reputation, is pretty damn cool.
Not sure why there are so few other good examples to point to though.
There are lots of examples like this in Haskell, where you come to a point at which the abstractions provided to you don't work, mostly when the problem has more structure than you can hope to capture in the type system and some generic operations. In an imperative program it is much easier to "teach" or "tell" the computer what to do, when the compiler or language can not do it for you, whereas in a pure functional language you essentially have to give up at that point.
Similarly, if you're looking for a language that will read and write like a specification for your problem domain, so that writing your program has the side effect of doing half the work of proving your program correct, Golang is also not a good choice.
What's worse, those two approaches to solving programming problems are compatible with each other. Lots of sharp programmers deeply appreciate both of them, and are used to languages that gracefully provide both of those facilities. If that describes you, Golang is a terrible choice; it will feel like writing 1990s Java (even though it really isn't).
There are two kinds of programmers for whom Golang will really resonate:
Python and Ruby developers who wish they could trade a bit of flexibility, ambiguousness, or dynamicism for better performance or safer code seem to like Golang a lot. Naive Golang code will outperform either Python or Ruby. Golang's approach to concurrency, while not revolutionary, is very well executed; Python and Ruby developers who want to write highly concurrent programs, particularly if they're used to the evented model, will find Golang not only faster but also probably easier to build programs in.
Systems C programmers (not C++ programmers; if you're a C++ programmer in 2014, chances are you appreciate a lot of the knobs and dials Golang has deliberately jettisoned) might appreciate Golang for writing a lot like C, while providing 80% of the simplicity and flexibility value of Python. In particular, if you're the kind of programmer that starts projects in Python and then routinely "drops down" to C for the high-performance bits, Golang is kind of a dream. Golang's tooling is also optimized in such a way that C programmers will deeply appreciate it, without getting frustrated by the tools Golang misses that are common to other languages (particularly, REPLs).
At the end of the day, Golang is overwhelmingly about pragmatism and refinement. If you're of the belief that programming is stuck in a rut of constructs from the 1980s and 1990s, and that what is needed is better languages that more carefully describe and address the problems of correct and expressive programming, Golang will drive you nuts. If you're the kind of person who sees programming languages as mere tools --- and I think that's a totally legitimate perspective, personally --- you might find Golang very pleasant to use. I don't know that Golang is a great language, but it is an extremely well-designed tool.
I don't know many (TBH none) c programmers that likes or actually uses go. The thing is that as for c++ if you are still writing in c is just for few reasons: portability (in terms of embedding your library) and speed. Especially the former seems very important.
EDIT: I know => I know personally or I follow.
Most of the systems C programmers I know, who admittedly work on large distributed systems, like Go.
I'll give you two, Rob Pike and Ken Thompson. Ha! :)
Why do people make generalizations like this, Language wars are so much fun but we really do waste a lot of time on them.
A quick search for Go REPLs gave me many results, e.g. https://github.com/rocky/go-fish "Yet another Go REPL"
In all those years of Scheme, Ruby, Python, Haskell, Scala I have never used REPLs for anything other than tutorials or trying out something quickly.
> that Go doesn't have a good REPL
What makes you think that the Go REPL is not a good REPL? Have you actually tried it? Probably not, because you do not care as much about REPLs as you think do.
Really shines when the language / REPL has decent introspection, is able to break out into the REPL prompt in the middle of your code with in-scope identifier lookups, and you're dealing with lots of libraries that you don't necessarily have encyclopedic knowledge of, yet need to get the job done under time pressure.
At least that's how I use REPLs, most usually, pry in Ruby.
If languages used in industry have had something for decades it does not automatically mean that it's a good idea. Go reconsiders a couple of things that once were thought to be good ideas like class inheritance, exceptions, generics and questions their net benefits.
-or-
If you are looking for X, use X.
When single threaded top-down Python is too slow for a particular task, of late I find it easier/cleaner/faster to use Go routines than multiprocessing / threading in Python, because of the way concurrency was designed in Go, but added to Python.
> "ability to write concurrent code in straight-line fashion rather than with callbacks X"
Same concept or different point?
There's this common attitude of "if you want feature X and Go does not have it, Go is not for you." To some extent it's not surprising since there was confusion about what niche Go hit when it first came out. But when there's repeated patterns in critiques of Go coming from very smart people, it's probably worth paying attention rather than saying it just doesn't fall into the language's sense of "pragmatism".
FWIW, I'm a Python programmer who loves Go. Despite all its good stuff, though, we shouldn't remain content with what we have already.
If there's a debate to have here, it's about what word better captures the point I was trying to make than "pragmatic". But that's an incredibly boring debate, so, I opt out.
Golang comes pretty close to flat-out rejecting object orientation. It's only barely more object-friendly than C is. If you're the kind of programmer that wants to model a problem domain or build code with the Smalltalky feel that Gang of Four patterns give Java and C++, you will also hate Golang.
Generics might happen in the future (the more Golang I write, the less excited I am at the prospect), but a richer object model seems very unlikely. If you want to hang your argument on polymorphism rather than generics (I applied the principle of charity and assumed that's what you meant), the argument gets less valid, not more.
If you want to write generic methods using your own types, you can define an interface to operate on, and then create types which conform (or wrap more basic types to conform) - as this article demonstrates after it sets up a straw man to criticise golang with. I quite like that approach, though it does depend what sort of libraries you're writing, and what sort of types you're operating on - a maths library might be painful for example but if you're operating on your own types anyway, using interfaces is no great burden.
I hear that a lot. That's not really an argument. People also enjoy stupid things, including things that hurt them, like drugs.
Well, it certainly isn't a convincing argument that it is the best of all possible languages, but it does lend weight to it being worth a look in its current form. Personally, compared to other languages I've been forced to think in (Java, C, C++, ObjC, Ruby), it comes out favourably, but I'm quite happy to accept that some people might think it is stupid, dangerously simple etc, etc. and listen to their reasons why - there's room for more than one language in the world.
Sounds like he is looking for Forth or one of its decedents (e.g. Factor). That is pretty much the definition of how you do Forth development.
There are just tens of little ugly things Go does and the result is, well, even uglier. Writing four functions for every collection to be sorted, writing x = append(x, foo) everywhere, shitty namespacing that prevents you from writing list := list.New() and so on and so forth. Even C is more elegant, and I would probably prefer to use C, if only C came with a library manager like rubygems or go get and a decent repository of libraries. I would even prefer Java if it produced native binaries and had an integrated library manager.
I love Golang namespacing rules. They do exactly what I need them to do to allow me to call into other people's code using the right function calls, and nothing else. I think Golang's namespacing is a high point of the language.
No, vector::insert() is the common idiom and mutates in place. It'd be written `x.insert(x.end(), foo.begin(), foo.end());` For single elements, vector::push_back() is the common idiom, and also mutates in place.
func ReadFile(filename String) {
file := file.Open(filename)
}
In Go you have to invent a new name, so invariably you will see a lot of: theFile := file.Open(filename)
aFile := file.Open(filename)
readFile := file.Open(filename)
depending on who wrote the code. f = file.open("a.txt")
out_file = file.open("b.txt", file.WRITE) typedef int foo;
foo main() {
foo foo = 0;
return foo;
}a couple of times I just changed the name of the import, as you sometimes do in Python:
import (
urllib "net/url"
)url := urllib.QueryEscape(...)
tada!
Really?!? Available in modular languages since Mesa days (mid 70's).
Reading a golang program is simple because you don't have to chase class hierarchies very far. I personally find polymorphic code to be a detriment to team projects. Anything that hides implementation is a hit on readability.
In a weird way, it reminds me of BLISS[1]. BLISS had this relationship to assembler that "made it manageable" while keeping things fast. BLISS was replaced by C pretty much everywhere that C took hold (one theory is that BLISS is the 'B' programming language, Algol is the 'A' language, personally I think BCPL is a better owner the the 'B' moniker). The things that C has issues with, memory management, networking, and multi-threading, Go takes on front and center. It keeps around some of the expressiveness and type checking that makes compiling it half the battle toward correctness.
Now that was kind of what the Java team was shooting for as well but with limited success. I feel like between Go and Java we've got some ideas of what the eventual successor language will look like. For me at least that is a step in the right direction.
> programming in Go isn’t “fun” in the same way that Python, Haskell, or Lisp is.
Yes, writing Lisp is much more "fun" than writing Go for me. But writing Go is much more productive and maintainable (both for solo projects and for larger groups).
In fact, this is almost an intentional "feature" of Go: http://aerokode.com/blog/go-is-boring
> The idea is that there’s simply no way that any group of designers could imagine how people will want to use their language so making it easy to extend solves the problem wonderfully.
On the other hand, there's no way of making a language so easily extensible while also maintaining relatively uniform idiomatic, design, and style conventions across a language community. Go very heavily favors the latter.
> In Lisp, CLOS (Common Lisp Object System) was originally a library. It was a user defined abstraction that was so popular it was ported into the standard.
CLOS is actually very similar in some ways to Go's structs. Both emphasize encapsulating data inside an "entity" (object/struct), and separating the notion of behavior from that entity. To quote one of the language authors from GopherCon[0]: "Interfaces separate data from behavior. Classes conflate them."
Lisp was "designed" (if you can call it that) around the principle that extending a language should be as easy as writing a program in that language. Go was designed around the principle that there should be only one dialect of the programming language, for the sake of cohesiveness. It's a stronger assertion of the Pythonic motto, "There should be one, and preferably only one, obvious way to do it".
[0] https://twitter.com/chimeracoder/status/459827405386162176
You've completely missed the article's point: users were able to create CLOS before it got integrated in the language.
The fact that users are able to create core language features has its drawbacks when it comes to cohesion in the language community. Lisp itself is a perfect example of this - codebases are immensely fragmented in terms of which libraries they end up using (Quicklisp is, in part, an effort to solve this).
Lisp was "designed" (if you can call it that) around the principle that extending a language should be as easy as writing a program in that language. Go was designed around the principle that there should be only one dialect of the programming language, for the sake of cohesiveness.
Both are legitimate philosophies for different use cases, but that's why it's kind of silly (IMHO) to compare Go to Lisp - the goals are not only different, but diametrically opposed in most ways.
Go, on the other hand, was designed and implemented from a single vendor in a handful of years. That makes it far easier to provide a single, coherent platform. Once you provide a coherent, complete platform you don't need your users to solve every edge-case by implementing their own language features.
Any language that doesn't provide some kind of code-that-writes-code workflow will eventually leave its developers dealing with frustrating boilerplate.
Not sure about this statement. As the OP said in order to trick the anti-features of go you need to come up with super verbose syntax. Which is easy that's true but when the project tends to be quite big the mission becomes hard.
Also the "go get" thing is neat for small projects but for larger project IMHO is just broken. Godeps or few sh scripts can alleviate this but definitely is something needed to be addressed.
I heard ASP.Net WebForms get this defense, that no other platform could handle the "enterprise" needs for maintainability and every other platform was just building a pile of cowboy spaghetti code.
Turns out it just sucked.
Well, an anecdotal counter-evidence is that we have some WebForms apps maintained by another team in our company and the developers from that team seem very happy and are productive enough to meet reasonable deadlines. I despise WebForms but that doesn't mean anything from a product managers perspective.
What does it mean for language to be "fun"? I have some intuition of "fun", but it doesn't play well with what are you saying. I'd say being "fun" means ability to solve your problems easily, concentrating on problems themselves, not on language pitfalls. Isn't it? That's pretty much synonymous (maybe a little broader though) to "productive". So I can't comprehend how language can be "less fun, but more productive and maintainable".
Go offers very little that's interesting or innovative and doesn't go out of its way to empower you in any particular way. It's fairly straightforward and tries to avoid gotchas, which is both good and bad. This means writing code is easy and you're unlikely to make a mess, but there are relatively few opportunities for making your code read better or to structure it better.
In a nutshell: Writing code is more of a drudge than an art.
For example, I was recently writing a processor for some data that came in an XML file format. I figured maybe throw it at Go since it was a lot of data and Go has pretty good XML support. In Go, this was a lot of looping and copying and basically nothing all that confusing but it just felt like busywork. For fun, I decided to write it in Clojure as well. The Clojure version was much more pleasant to read, with all the loops disappearing into simple compositions of map, reduce and filter. It felt nice to be able to easily express things in such an elegant way instead of on a more machine-like level.
(To be clear, I am not a great Go programmer and wouldn't want to speak for the Go community, though this is something the language creators seem to agree with. I'm just trying to explain what how I understand this stuff.)
That's true of the features looked at individually. I think its particular combination of design choices is interesting and novel ("innovative" requires a value judgement that I am not quite ready to make in Go's case; though I think the momentum its gained in certain areas is quite likely because it does offer something that is innovative in its utility even if its not immediately apparent why the particular combination of features it provides should be.)
Go did not strike me as a language I would enjoy writing, despite the strengths it surely has in some areas. I would just be giving up other strengths I prioritize more highly.
Go is relevant where you want pretty good performances and concurrency with low memory footprint(unlike java) ,without using C/C++ and threads. But it's clearly not for everything.
I can't leave go, but indeed I think absolutely the same. The thing is that GO was designed to replace c++ thing that absolutely failed. So we have a python/ruby replacement with very old patterns (I think manual checking errors ie.).
Indeed I think go is an awesome language but sometimes I really feel like a monkey repeating myself over and over again.
(To me OCaml seems like a better replacement for a lot of what people are doing in go, but admittedly it doesn't have the same concurrency support)
I was so excited for GO to become a nice replacement to C++. GO has awesome build times. C++ has awful build times. This is partly due to all the extra work the C preprocessor has to do make sure all the headers are present.
The big lose for me is the fact that GO has absolutely no operator overloading. This is one of the biggest wins in C++, especially since I do lot of high-performance scientific computing. Overloading operators makes code a lot more readable and user friendly, in my opinion (I'm others will disagree, though). I'm aware that you can hack GO to mimic operator overloading but it involves hitting the vtable. And hitting the vtable is completely unacceptable in performance-critical code.
[1] https://groups.google.com/forum/#!msg/julia-users/-SGWPUBJKq...
While absolutely not implying that it's a reasonable alternative, someone could try implementing infix operators as a syntactic layer on top of Go (kind of a preprocessor). It might work to fix the use case presented in the OP (math operators being far more readable in their infix form).
Infix operators might just be implemented as a syntactic sugar layer after all, at least as a first draft; if you're able to parse a Go source file and its types in a way that when you see a sum expression, you already know whether both arguments implement a Numeric interface and/or Add method, you might be halfway through.
To clarify: I love infix operators and I'd love if Go added them, and I consider the above just a hack.
Completely true for scientific computing, but I've been subjected to libraries written in scala recently and operator overloading there has lead to some very difficult to read and use libraries.
> I was asked a few weeks ago, "What was the biggest surprise you encountered rolling out Go?" I knew the answer instantly: Although we expected C++ programmers to see Go as an alternative, instead most Go programmers come from languages like Python and Ruby. Very few come from C++.
http://commandcenter.blogspot.com/2012/06/less-is-exponentia...
I don't think Go was designed as a general replacement for C++, I think it was designed as a replacement for C++ for the things that Python was almost better than C++ for, but not quite.
EDIT: Though, OTOH, I do get the feeling that the people who designed Go largely are the type of people who feel that just-plain-C is a superior choice to C++ for most of the rest of the domain where C++ might be used, so they might view Go as a general replacement for C++, because they start with a smaller view of C++'s useful role than the market at large has.
Before using Go, I have always programmed with "modern" languages that use exceptions for error handling. So the concept of only doing manual error handling was new to me, but after a few months of golang I love it now and exceptions in python started to really annoy me.
In Go, I'm forced to do error handling right after every single call that will possibly return an error. While I thought that the resulting code looked ugly and repetitive, the result is a much more focused and intelligent error handling.
If i wanted the same granularity and robustness of error handling in python, I'd have to put a catch all try..except block around every single call .
Exceptions are a good time saver in stateless request based programs (like HTTP/web stuff) where it's sort of accetable if one request fails. I could just not care so much about detailed error handling, the worst that could happen is that i don't catch some error and the wsgi wrapper will catch it and return error 500 to the client. But building daemons in python is just plain painful. If I don't want my program to crash at some point I have to reckon that anything can raise an exception I didn't think of.
What's interesting with go is that if you can program, you already know it; all your time is spent building stuff, not learning the language. And when it comes to building stuff, Go is just straightforward.
You should look into Rust. It sounds like it might be more like what you're looking for.
On the other hand, if that's the kind of thing that excites you, Rust is a really great option right now.
But I find it unfortunate that type switches must have single type cases. For example, it's too bad this doesn't work:
http://play.golang.org/p/a4j1I6Oug-
The OP's complaint would be minor if the compiler would auto-unroll the multi-type case clause.
> Extensibility
One really great thing about that is how consistent it is. Every func in Go has a unique identifier: the package import path and the func name pair. This makes it possible to build tools like godoc.org and the `doc` command that let me look up the exact behavior of (unfamiliar) code.
In this case, I can go to godoc.org/math/big#NewInt or type `doc big.NewInt` and see:
// NewInt allocates and returns a new Int set to x.
func NewInt(x int64) *Int
In fact, it's so predictable that I don't have to think. As long as it's Go code, if I ever run into an unfamiliar func F of package P, I can always go to godoc.org/P#F or `doc P.F`. No searching, just an instant lookup. If I need to do 30 such lookups to solve a task, it makes a big difference. This applies to _all_ 3rd party Go packages. That is big.On the other hand, something like `x + y` is magic to me. I know that computers work with bytes at low level, and I want to be _able_ to understand what happens on that level. I understand and accept such magic for built in types. But I certainly wouldn't want to be reading a 3rd party Go library code that says `x + y` on its custom types. Where would I go to find out what that custom plus operator does? How does one make an unexported version of a plus operator? There'd be less consistency, more exceptions and rules, more variations in style and less tools that can be built to assist/answer questions about Go code.
> The Type System
I don't have time to cover this atm, but there are some advantages to the explicitness and verboseness of Go's approach. Can you think of any?
I'm not suggesting it's the best it could ever be, just that there are both advantages and disadvantages that should be considered.
All that said I hope Go adds D like compile time code generation and static typing or [D,Rust] gains better tooling and HTTP service oriented libraries and APIs that are as well written as the Go standard library packages are. Secondly I hope [D,Rust] sees how awesome having a common automatic format, build, and test tool is. In so few language is the testing package as simple as Go's. In so few languages is the build process as easy as Go's.
That is why Go attracts mainly people from scripting languages (they get a bit more type safety and better performance) and C (they get a bit more type safety and less errors). Coming from other languages Go is not that attractive. I'm hoping for Rust to succeed.
I haven't tried them yet, but it looks like their fun.
Julia generally favours composition over inheritance. You might be interested to look at GTK.jl, its widget/window system.
If the OP is looking for a C++ alternative and knows Haskell, Rust is also an interesting alternative, although it's at a very early stage of development.
Also, I personally look at Nimrod as a faster and slightly cleaner Python with a few extras, and I don't try to break the compiler using all of its cutting edge features. If you use it that way you will be happy.
Go is a something like C, but with a few more features plus GC and come neat concurrency facilities. Why would anyone expect that to be anything like Haskell, or even to have a type system even approaching that kind of power?
We had introduction to parsing and basic language processing.
Reading a go source file is like following a for loop. It's quite technical. Reading a Java source file can be a case of trying to figure out the high level abstractions of the program.
>b.Mul(b).Sub(big.NewInt(4).Mul(a).Mul(c)) >Or in Haskell
>b * b - 4 * a * c
umm.. correct me if I'm wrong, since I'm not well versed in either Haskell or Go, but doesnt the Golang version read better in terms of scoping. I mean just by reading the Go version, I know what it will evaluate to, but in the Haskell version I dont know the precedence order just by reading.
You can ask for it in GHCi (the REPL):
> :i (-)
> [...] infixl6
> :i ( * )
> [...] infixl7
So ( * ) has precedence over (-). The expression is then:
(b * b) - (4 * a * c)
Personally, I don't know if infix syntax is truly overall more readable than purely prefix/postfix syntax, or other such uniform representations. It might be for arithmetic, because it is so ingrained, but the precedence order was never hammered into me to such a degree that I learned it automatically by heart; I used to defensively make more parenthesise than I really needed to, just in case.
edit: I don't know go, but I assume the go example is intentionally unreadable. But complaining about infix multiplication and subtraction is... curious.
However, my general call on that is that if you need your language to provide overloaded arithmetic operators, stick to languages that actually want to give that to you. It comes up a lot in language discussions because it's such an easy example to type out in a couple of lines, but in practice I don't think you see a lot of need for exotic int types being used pervasively throughout your code. Don't use Go for that. Don't use any language that doesn't do operator overloading. But this is far less a common use case than seems to be supposed... a variant of the "look under the streetlight" fallacy, I think.
Go's really for heterogeneous concurrent business- or server-like programming. It isn't a language for mathematics, and the burst of libraries I've seen in the last couple of weeks that seem to be focused on that is bizarre to me. Go isn't good at that, isn't meant for that, and probably never will be. Go's nice for the very large niche that "business- and server-like programming" is but it's not so fantastically wonderful in every way that I'd want to work too hard to make it work in a niche it's not really suited for.
This particular piece (by a high school student, as an aside) starts off trying to create a surrogate for generics in Go.
Don't.
Here's the thing -- most of these posts are not about people making real code, but people making -toy- code. Where every function is all things to all people.
The number of times I've needed a generic abs in my life -- zero.
The number of times I've needed a double floating point abs in my life -- every single time.
That's the thing about generics and real, actual world code: Your types are generally much less amorphous than you think. They really are. This illusion that everything needs to be everything just does not hold in the real world.
But it is always the tiring example used against Go. Boring.
What about a generic max() or min() function?
This is an example of a simple "generic" in Go, as I recall it:
type mytype struct {
mydata interface{}
}
The casting this requires felt like a step into the past when you're used to eg the STL.For example, the OP mentioned that using a stack in Go requires casting from `interface{}`. But this is patently ridiculous. Most people who need a stack in Go just use a slice: https://code.google.com/p/go-wiki/wiki/SliceTricks --- Is this a bit messier and limited than a container type suited to stacks? Yes! But it gets the job done the majority of the time. Therefore, it's not as big of a problem as the article leads you to believe.
Not all things require clean polymorphic container types. Sometimes you can get by with less. And when you need more, you're going to feel a bit of pain with a less expressive type system. It's all part of the trade off. But it's not good to represent this as a scenario where it's all just bad stuff all the time.
But, to be fair, in the Go world, both mechanisms are used. It depends on which costs are important.
x = append(x, a, b, c)
[0] http://golang.org/pkg/container/list/The number of times you'll need a generic map or fold algorithm to operate on those structures: many, many times.
https://github.com/petar/gollrb
So if you need a data structure like this, you can do it without much trouble without generics. Perhaps you don't feel that solution is as clean, but it's certainly pretty easy to do.
NB that golang has not ruled out generics, it's just not something they felt compelled to put in initially, and not many people who use the language miss them.
The abs example could be reduced to:
import "github.com/joeshaw/gengen/generic"
func abs(x generic.T) generic.T {
if x < 0 {
return -x
}
return x
}
You could then generate different type-specific versions: gengen abs.go int32 | gofmt -r 'abs -> absInt32' > abs_int32.go
gengen abs.go float64 | gofmt -r 'abs -> absFloat64' > abs_float64.go
...
The downside is that the API is annoyingly non-generic (a different abs variant for each type) but at least you didn't have to type it in a bunch of times.I agree that abs() is kind of a toy example, but this approach has helped me a lot for various slice operations like indexing and deleting.
func abs(x Top) Top {
switch v := x.(type) {
case int32:
if v < 0 {
return -v
}
case int64:
if v < 0 {
return -v
}
case float32:
if v < 0 {
return -v
}
case float64:
if v < 0 {
return -v
}
}
return v
}I did have to put "return x" as the last statement, though, not return v. And I'm not sure I'm happy about an "abs" that happily returns a string if fed a string, but, well, that's Go.
Relevant bit of the spec: http://golang.org/ref/spec#Type_switches
But the short variable declaration in the type switch does indeed save the casts the OP was complaining about.
Even more correct and horrible: http://play.golang.org/p/ZMQKQhuUQT
For instance, pass a positive int16 and you get the right answer, but pass a negative int16 and you get a useable but wrong answer instead of nil from the original.
Thanks for the downvote :-)
switch v:= x.(type) {
case int32, int64, float32, float64:
if v < 0 {
return -v
}
}
Go has some neat improvements to the switch statement: http://golang.org/doc/effective_go.html#switch