16 ms·
Everyday hassles in Go
- TeeWEE 12y agoWhile the author has a lot of valid points, he forgets the goal of Go. Go was designed as a simple language, that is fast, but has similar power to existing dynamic languages such as python. The tradeoff in these designs are to prevent tuple types, always keep using structs, prevent using algebraic types over structs. Allow for nil, but try prevent common Null errors etc. Haskall is theoretical a much better language. But Golang was designed to be practical & simple over being mathematically sound, and theoretical better.
- kasey_junk 12y ago> Go was designed as a simple language, that is fast, but has similar power to existing dynamic languages such as python. I'd like to see a citation for this as I've never seen this as a stated goal of golang. In fact, if it were the stated goal that is one of the most damning arguments against golang as it very clearly fails at this task. I've been under the assumption that golang was designed to make writing/deploying/managing simple web services across a wide variety of machines and across a wide variety of teams. While I'm still reserving judgement on it accomplishing this goal, I'd say it is much more likely to accomplish this than trying to have similar power to python.
- Someone 12y agohttp://golang.org/doc/ http://golang.org/doc/: "Go compiles quickly to machine code yet has the convenience of garbage collection and the power of run-time reflection. It's a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language." That comes reasonably close.
- Cyther606 12y agoFor a Python-like core language with an expressive type system that is simple, clean and immediately absorbable, you're really looking for Nim, not Go. The following produces a single binary with native code generation via compilation to C, no VM: import rdstdin, strutils let time24 = readLineFromStdin("Enter a 24-hour time: ").split(':').map(parseInt) hours24 = time24[0] minutes24 = time24[1] flights: array[8, tuple[since: int, depart: string, arrive: string]] = [(480, "8:00 a.m.", "10:16 a.m."), (583, "9:43 a.m.", "11:52 a.m."), (679, "11:19 a.m.", "1:31 p.m."), (767, "12:47 p.m.", "3:00 p.m."), (840, "2:00 p.m.", "4:08 p.m."), (945, "3:45 p.m.", "5:55 p.m."), (1140, "7:00 p.m.", "9:20 p.m."), (1305, "9:45 p.m.", "11:58 p.m.")] proc minutesSinceMidnight(hours: int = hours24, minutes: int = minutes24): int = hours * 60 + minutes proc cmpFlights(m = minutesSinceMidnight()): seq[int] = result = newSeq[int](flights.len) for i in 0 .. <flights.len: result[i] = abs(m - flights[i].since) proc getClosest(): int = for k,v in cmpFlights(): if v == cmpFlights().min: return k echo "Closest departure time is ", flights[getClosest()].depart, ", arriving at ", flights[getClosest()].arrive Statistics (on an x86_64 Intel Core2Quad Q9300): Lang Time [ms] Memory [KB] Compile Time [ms] Compressed Code [B] Nim 1400 1460 893 486 C++ 1478 2717 774 728 D 1518 2388 1614 669 Rust 1623 2632 6735 934 Java 1874 24428 812 778 OCaml 2384 4496 125 782 Go 3116 1664 596 618 Haskell 3329 5268 3002 1091 LuaJit 3857 2368 - 519 Lisp 8219 15876 1043 1007 Racket 8503 130284 24793 741 Not only is this syntax far more approachable for anyone who likes Python, as opposed to Go, Nim is actually suitable for systems and embedded programming. Optional GC and manual memory management makes Nim one of the few up and coming systems programming language that ventures into C territory while still being safe and pragmatic enough for general usage. http://goran.krampe.se/2014/10/20/i-missed-nim/ http://goran.krampe.se/2014/10/20/i-missed-nim/ https://github.com/Araq/Nim/wiki/Nim-for-C-programmers https://github.com/Araq/Nim/wiki/Nim-for-C-programmers
- rjberry 12y agoI dislike it when people say languages are either 'practical' or 'well designed'. As if a language is only useful if it's not built on sound mathematical ideas ... Generics are not a particularly new idea and nobody who uses language that implement them yearn for the days when they weren't around. See Paul's post on the idea that 'worse is better': http://pchiusano.github.io/2014-10-13/worseisworse.html http://pchiusano.github.io/2014-10-13/worseisworse.html
- jbooth 12y agoThe point is that you reach an area where the mathematical ideas don't map perfectly to the underlying functionality you're providing. You can make your language "unsound" by violating those mathematical principles, or you can make something like the I/O monad. It is indeed "soundness" vs "practicality". EDIT: Oh, and that link seems to have misunderstood the 'worse is better' philosophy -- C++ isn't the champion of 'worse is better', C is.
- rjberry 12y agoPaul explains fairly well why he thinks C++ is a good example of "worse is better", including quotes from the language designer to that effect. I think when you get to more complicated (or at least alien) abstractions like the I/O Monad, it's not about whether it's practical to build software with it. It's perfectly practical - I know people working at big investment banks writing large scale software in Haskell, and they don't have any issue with it. What it comes down to is whether the people you work with will understand or want to invest the amount of time required to learn those abstractions. If you're working with very talented programmers, that might be yes. With the majority of programmers it is probably no. But we're not talking about the I/O Monad. We're talking about generics, which are not difficult to understand, and that Go lacks them is a shame, as it means that whole layers of abstraction are not available to the programmer, so they end up having to spend more time writing boilerplate.
- jbooth 12y agoSo he invested time in building up his straw-man before tearing it down? The problem with being in such a rush to confirm your own worldview is that you don't learn anything from anyone else's. The 'worse is better' philosophy is about valuing simplicity over completeness, specifically in the context of UNIX/C vs Lisp machines back in the 80s. How do you think most of those people feel about, say, the STL?
- bsaul 12y agoAlthough i'm still very unsure about rob pike's argument that go don't need generics since it has interface, a recent experience : After having implemented a mini web services in go and being fed up with its limited type system, i decided to stop coding in go and start recoding my project in java using what is often advertized here as the most minimal framework : dropwizard. Well, i downloaded the framework, configured maven, started the hello world tutorial, and quickly found myself dealing with 2 xml files, 1 yaml file, multiple classe files ecerywhere, and couldn't get the whole stuff work immediately. Then i realized that my golang implementation was already working, and that i completely understood my code and its potential performance characteristic, without having to have deep knowledge about the jvm internals, things like sevlet containers, or how the whole stack would deal with my global variables in a multi-threaded context. All my code was just one simple program. My temporary conclusion right now is that golang type system is indeed extremely shite, but that if what you need is to develop simple yet efficient web services, it doesn't matter that much.
- tinco 12y agoAlthough I am a Ruby programmer and would hate to have to work in Java, I do adore C# (it is a near-perfect language). And I feel I need to defend this certain aspect of statically typed pre-compiled languages. 1. Dropwizard is not a minimal web service library, it's a minimal web service framework. You could've used just a library, for example this[0] one, and be done in 10ish lines boilerplate that you fully understand. 2. That would also mean you wouldn't need Maven or any XML configuration. Just a bash script or a Makefile that invokes your compiler. 3. There's 3 ways to deal with global variables in the world. The first is plain allow them, and let everything go to shit when two threads access them at the same time. That's how most languages, including Java, do it. The second is allow them, but never allow more than one line of execution at the same time, this is how many scripting languages like Javascript and Ruby do it. The third is 'not' allow global variables at all, and instead only expose shared state through mechanisms that explicitly deal with concurrency like pipes/messages/locks, this is how Haskell and other pure languages do it. (There's also STM, but that's a bit more complex) Once you know which of the three your language does, you'll know exactly how to deal with it. No need to be uncertain about it. 0] http://docs.oracle.com/javase/7/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/HttpServer.html http://docs.oracle.com/javase/7/docs/jre/api/net/httpserver/...
- kator 12y ago"Every computer language is an imperfect way of describing a potential solution to a poorly understood problem" -- Me I find it interesting when people wax poetic about how one language is better than another and how if we just did x, y or z then we'd have this perfect solution. That said I appreciate the author's write-up of some challenges with Go. In the end the reality of any "product" is building what the user's need not what they ask for. That said I do worry that the Generics argument seems to be slowly approaching a religious war that will distract people from the other enjoyable aspects of Go. Worse yet it may calcify the Go development team in a way that will keep them from addressing the basic issues that generics might help solve. Either way Go is just another computer language and I'm happy to use it often to solve problems I'm working on. That said I use a lot of computer languages every week when I'm working on stuff, none of them are perfect and my solutions to the underlying problems are fragile and constantly evolving as the problems unfold. This is the nature of our business, to constantly do battle with poorly understood problems using imperfect tools in a world where we are fooled into thinking everything is black and white because at the core of our technology everything is a 0 or a 1. "One Computer Language to bring them all and in the darkness bind them".. LOL
- nine_k 12y ago> my solutions to the underlying problems are fragile ... This is the nature of our business I think this is a mistake. A lot of business is run this way, though.
- dons 12y agoLanguages may not be perfect, but language features can be compared, and some features are strictly more powerful than others. There is scope for legitimate criticism of language design based on the expressive power^1 of their features. In this case, generics would make Go strictly more expressive, as, without it you must write O(n) more code or perform a global refactoring to simulate it. 1. http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.4656 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.4...
- skybrian 12y ago
- lmm 12y agoAgree with a lot of this, but I find the lack of any punctuation one of the most confusing things about Haskell code. Map String Any Is that a function call? A type declaration? What's a parameter to what? The go style map[string]interface{} is, much as I love to hate on all things go, much clearer.
- friendly_chap 12y agoThe reason Map String Any does not contain any special symbols specific to that certain type is because it is not a built in special type like the Go map[string]interface{}. It is just a regular type parametrized over two other types. And kinda that is the point - being expressive enough to describe a map type without explicit support.
- dons 12y agoThere's nothing a priori clear about punctuation like [ ] { }, you're just used to seeing lots of syntactic markers.
- lmm 12y agoSure. But many languages have a standard way of defining what's a function declaration, what's a function definition, what's a type definition, what's a function parameter, what's a type parameter, what's a function call, what's a type instantiation; it doesn't really matter what the specifics are, what matters is that there are standard indicators that stand out from the code (and I think there is a sense in which []{} are a priori more visible in the middle of a paragraph than letters are). Haskell doesn't seem to have that; any piece of Haskell code tends to look like a smooth surface of words separated by spaces. Function? Words separated by spaces. Type? Words separated by spaces. Instance? Words separated by spaces. There are no visual handles to latch onto, nothing to help you realise how this stream of words separated by spaces forms a tree structure (AST).
- dons 12y ago> There are no visual handles to latch onto Haskell uses syntax and context to distinguish identifiers as follows: - variables, lower case initial letter - constructors, upper case initial letter - type variables, lower case initial letter - type constructor, upper case initial letter and similarly for classes and modules. And of course, white space is function application. So you know if it is a variable or a constructor by looking at the first letter. And you know if it is a value-level variable or a type-level variable (or constructor) by context (types can only appear in certain places, e.g. on the right hand side of `::`). But, yes, they all look like words. They're not ambiguous though. :)
- NateDad 12y ago"Why Go is not Haskell"
- erglkjahlkh 12y agoWhile I understand your comment, I have to disagree. Programming languages should be kind of boring, and support the average developers' work. That is why Haskell will ultimate fail and fade away - most of the developers on this planet are simply not skilled enough to touch any of that stuff. Attempting to add all Ninja concepts to a language will just lead to a massive failure. Go does a very good job on forcing even the most average developers to reach surprisingly succinct and elegant solutions. However, the lack of generics really forces in some situations to either use the reflection or stop being very DRY or elegant. Go wouldn't have to implement full generics to fix that. Just adding something similar to what interfaces are to methods for variables would do, without the rest of the moving parts.
- loosescrews 12y agoSo type classes?
- waps 12y agoFirst of all, you're making the enterprise java argument. Which is valid, but drives me to suicide. Furthermore ... Go ... succinct ... elegant ... using reflection as an alternative to generics ... In my experience Go is neither succing (if err { ... } one-statement if err { ... } one-statement if err { ... } one-statement). It is extremely inelegant because due to the confused sequence of statements it isn't possible to keep your thoughts on what the method is doing, as there are constant error handling concerns everywhere (or regrets/TODOs about error handling to be completed in the future ...) Is this (if this doesn't refer to itself or the sentence it's in, return that information to the caller manually so he can ignore it) somewhat (if the above statement is not and adjective you have a problem with your understanding of english, report to the relevant authorities) unclear (if un doesn't result in the reversal of the meaning of the word clear, we have a problem and should inform the main sentence interpretation routine that understanding is flawed) perhaps (missing error checking) ? (if the above is not punctuation, report back that your browser is probably not using the correct character set) Using reflection as an alternative to generics is horrible in lots of ways, but just mentioning a few : no type safety (not even a decent verification you're passing the correct number of arguments). It's extremely long code, full of edge cases (such as arrays being a value type and slices being a reference pointer despite differing only in a single character). And it's sloooooooooooooow. As in ruby slow. And you forgot Go crashes. If you think C++ error messages are long, you haven't seen a nil-pointer dereference in Go.
- pothibo 12y agoOne thing that is perhaps counter intuitive is how you do a lot of for loops compared to other languages (Compiled/Statically typed included). Once you let go your previous expectations, Go gets a lot nicer to use. The amount of for loops you will write will also makes it obvious when you start doing O(n^2) operations in your methods. Same can be said with variables declaration and error verifications in Go. They are annoying at first, but then you understand by reading your code the places where error can occur or where you decided to ignore errors (By using _). It's a different approach and it's refreshing.
- frou_dh 12y ago> ... error verifications in Go ... you understand by reading your code the places where error can occur or where you decided to ignore errors (By using _) This compiles: package main import "errors" func main() { f() println("hello erroneous world") } func f() error { return errors.New("boo") }
- cjslep 12y agoSure, you can fail to capture any return variable (not just errors) in lots of languages. What is available to Go that isn't in, say, C++ or Java is the "black-hole variable" marked with the underscore _ so its very much a stylistic choice to insert it in Go where errors would be returned. Applied consistently, you can gain a lot of readability. But it is very much a stylistic choice.
- NateDad 12y agoWhich you can catch with a linter like https://github.com/kisielk/errcheck https://github.com/kisielk/errcheck. Errors in Go are just values. There's nothing "more wrong" about ignoring a return value that is an error or one that is file handle, for example. And in cases where a function returns an error and a value (where the error generally indicates the validity of the value), you'll get a compile error if you don't check the error. That's pretty good for basically zero overhead.
- 12y ago
- nhaehnle 12y ago> For those who are bothered about the exponential algorithmic complexity of nub There is nothing exponential about nub. Given only equality comparisons, detecting and eliminating duplicate elements requires quadratic running time.
- friendly_chap 12y agoYou are right! Others noted that mistake as well.
- jmnicolas 12y agoIf the author reads this, I think he's confusing "quiet" and "quite".
- im_dario 12y agoThis article has some good points but I'm going straight for the first one: I don't miss generics. Indeed, they are useful. I use them in Java every time I find a good reason to do it. So, I should say in another way: I don't miss generics in Go. Given my experience [0] in Go in the last years, I realized that if you miss generics in Go, your code is trying to cope with too much. I didn't miss them when I developed Mergo [1], a simple library to merge structs. I think we all agree if we should rewrite this in Java (or other language with similar type system) we would use generics at some point. [0] https://github.com/imdario?tab=repositories https://github.com/imdario?tab=repositories [1] https://github.com/imdario/mergo https://github.com/imdario/mergo
- friendly_chap 12y agoDid you miss it when you were working on larger codebases? The library you mentioned clocks at 500 LOC, and while the LOC metric is pretty inaccurate, it takes a lot more time to really miss language features.
- NateDad 12y agoI've been working on Juju for 18 months, which is over 250k LOC and have not missed generics at all.
- im_dario 12y agoNo. I didn't. I have around 2K public LOC in several projects (I can't check now my private projects, I guess I had typed more than that) but I would trust better NateDad's experience. I have two years of sustained Go usage (since end of 2012) and never missed them.
- deleted 12y ago[deleted]
- colin_jack 12y ago"I realized that if you miss generics in Go, your code is trying to cope with too much." Was wondering what you mean by that (not disagreeing just interested)?
- ufo 12y agoThe article mentions many uses of generics but it doesn't go over one of my favorites, which is that parametricity gives you "theorems for free". For example, I recently wrote a compiler in Ocaml for a scripting language. The type I used for the syntax tree has lots of type parametsrs: type ('id, 'str, 'enum) stmtf = (* big ADT definition goes here... *) The 'id type parameter is the type of identifiers (names), 'str is for strings (they get interpolated) and 'enum is for constants. These type parameters give me some flexibility. When the parser builds the first syntax tree everything is still a string: type syntaxtree = (string, string, string) stmtf and after a pass to bind names the strings get converted to more informative types: type boundtree = (nameId, interpolation, string) stmtf Up to now, we could get this flexibility by being untyped and defining all these fields in stmtf as "void pointer" or "interface". But the generics lets us make everything type safe. Central to this is the "functor map" over stmtf: val map_sstmtf: id: ('i1 -> 'i2) -> str: ('s1 -> 's2) -> enum: ('e1 -> 'e2) -> ('i1, 's1, 'e1) sstmtf -> ('i2, 's2, 'e2) sstmtf It takes 3 functions telling what to do to the id, str and enum fields, respectively and converts the stmtf by applying those fucntions to each field. The neat thing is that in the implementation of map_stmtf if we forget to apply apply one of these callbacks to one of the fields the code would not typeckeck. The code also won't typecheck if we apply a callback to the wrong field - say apply the "id" callback to a "str" field. This lets us catch at compile time bugs that wouldn't even have been caught at runtime because in the initial syntaxtree both "id" and "str" fields are represented by "string" and are thus prone to being confused with one another. Both of these turned out to be pretty useful as I evolved my language and changed the structure of my syntax tree. Liberal use of type parameters also gave many other benefits. For example it was trivial to modify the tree to add a line number next to all identifiers, all I had to do was update the type definition and then see the compilation errors to find the parts of my code that had to be updated. type syntaxtree = ((position * string), string, string) stmtf Finally, one extremely neat trick is that you can use type parameters in some places where you would have used recursive types. This pattern is described pretty well in this post I'm linking to and its the sort of thing that you can't really do without generics. http://lambda-the-ultimate.org/node/4170#comment-63836 http://lambda-the-ultimate.org/node/4170#comment-63836
- gws 12y agoEvery time I read an article criticizing Go I end up appreciating it even more. Maybe it's because I've never felt the need to use generics and in all these articles the examples they give are functions of a few lines that would be quicker to write 2-3 times for different types than remembering generic syntax. Maybe it's because they exalt one line functional functions over a nice, simple, easy to read FOR loop when the former are so difficult to read, figure out what they really do, what is the performance cost, debug... Maybe it's because of the bogus examples they give like criticizing > file, _ = os.Open("file.txt") > file.Chmod(777) for not handling explicitly a possible error when it's just because the example is ill written and the proper code is > file, err = os.Open("file.txt") > if err != nil { > ... handle error ... And here I stopped reading the article, it's always the same arguments over and over: more elegant and complex code vs. the un(cool) but oh my, so much simpler Go code. What I find really amusing though it's how people are so smug in their writing, pointing out the "obvious errors" (billion dollar mistakes!) that the Go authors made and their "ignorance" of proven modern programming language constructs they could implement in Go. There are two possibilities here, pick your preferred one. 1) Pike, Thompson & co. made obvious errors in designing Go because of their ignorance of programming languages and/or ineptitude 2) These bloggers claiming obvious errors in Go design don't really fully understand the trade-offs involved in what they ask for and ignore the fact that the Go authors have carefully thought about them and optimized accordingly I will go back to programming in Go, I'd take writing for loops all the time vs. writing a one liner in Haskell and then agonize over using the lazy or strict version of it :)
- kasey_junk 12y agoI think there is a third option that you are ignoring. Pike, Thompson & Co. are designing for a different problem set than the blog authors. Golang seems to shine at very simple, concurrent tasks that can be passed from one set of developers to another regardless of sophistication levels of those teams. It seems to fail pretty miserably at making a single sophisticated developer vastly more productive. It's what Java would have been if they'd thrown away the write once/run anywhere goal and never gone down the J2EE box canyon. There is nothing wrong with either goal btw, they just are in some ways opposites.
- 12y ago
- tarikjn 12y agoI couldn't agree more with this article. I did some Go a year ago and liked it. Then coming back to it a year later after having done some functional programming in Clojure, it's not just the lack of generics that disrupt my flow but also having to think about all sorts of imperative programming details like naming and creating variables and scope placements in cases that would otherwise be unnecessary in a functional language. I feel like I have been tainted by functional programming, and now Go feel like a joyless programming language which inevitably affect productivity. I am looking for a replacement programming language to solve small problems for which Python/Ruby would have traditionally been used, good file system, stream and networking APIs, but concurrency as a first class citizen, garbage collected, fast startup time. Doesn't need to be good at long running programs, but it would be great if it can evolve to play a repeat role in a large system/process without the hassles of having to duplicate every written line of code into tests to prevent small changes from breaking things. I am considering giving Haskell a try, but wondering if it might be overkill. Any suggestions?
- felipehummel 12y agoYou may try out using Scala as script language like this: "scala myScript.scala". The first startup times are slower, and even after that it may be slower than Python/Ruby but it still may be sufficient for your use case. Using "sbt ~run" (re-runs your program automatically at every file change) may also be an option.
- tarikjn 12y agoI don't see a reason why Clojure couldn't achieve the same startup time? I am trying to avoid the JVM startup time itself so that leaves out Scala/Clojure. I'd like to be able to have a fast startup time when, say, running a script with its containerized environnement, when it is done the container exits, so I can't leave a vm running. So I believe that leaves out JVM languages. Independently from that, I did try Scala before Clojure and found its grammar to be overkill and unintuitive so it wouldn't be my first choice.
- chrismccord 12y agoElixir sounds like it might be worth a look. Nice for scripting and as good as it gets for concurrent programming. Some of its design is inspired by clojure so you might feel right at home. http://elixir-lang.org http://elixir-lang.org
- fishnchips 12y agoI really like Go but have always missed generics. Wondering if some kind soul would fork Go, add generics and see how that fares.
- mikesf888 12y agogolang is a great language for devops to automate infrastructure tasks, but for application dev not so much
- NateDad 12y agoHave you used it in a real application? Is actually quite good.
- deleted 12y ago[deleted]
- zzzcpan 12y agoWell, I want Go to have refcounting instead of current GC, so my programs could guaranty latency. Single-threaded runtime, without all the locks, slow channels, races and so on, because there is no point in so much overhead and complexity for the majority of programs. More consistency couldn't hurt, so I wouldn't have to assign anonymous function to a variable just to return it. Fast regular expressions compiled by the language compiler into a native code could improve matching, parsing and validating consistency, instead of writing lots of loops everywhere. Compiler warnings instead of errors on unused variables, imports, etc. to allow faster prototyping. Better testing culture with meaningful test names and line numbers with actual failed tests. Table testing suggested by Golang team doesn't even support that with the means of standard library, you have to use your own runtime.Caller(1) wrapper. But generics? "Safer" type system? No, that's unnecessary complexity. As others pointed out, we already have Haskell and Rust for all those things.
- kasey_junk 12y agoI'm not sure if this is sarcasm or not, but I will assume not. If they made the changes you suggest golang would be come useless to me. That isn't to say what you want isn't valid, only that it gets to the heart of all these arguments. Every design decision comes with trade offs and you can't please everyone.
- zzzcpan 12y agoNo, it's not a sarcasm, but I didn't mean they need to replace those things, runtime and GC could be a choice, or it could be a completely different golang compiler. I've been itching to write one myself.
- erglkjahlkh 12y agoThe majority of the programs do not really need to guarantee latency. That being said, it is well known that Golang's present GC performs poorly. It presently fails to free memory in certain cases, and has pretty high overhead. There is work done on improving the GC to be fully concurrent, but that is still probably still 2-3 major versions away.
- jackielii 12y agoOk, we all know the problem, but do you have a solution? Have you considered the researches done by others, for example this one: http://research.swtch.com/generic http://research.swtch.com/generic
- frowaway001 12y agoYes, and Go apologists would also know at least one solution if wouldn't keep pretending that they can't keep reading the post until the very _first_ comment on the same page.
- jackielii 12y agoWhat I had in mind was that Go is an open source project, if C#'s solution is a good one, why not write up a proposal and try an implementation?
- frowaway001 12y agoWhy am I supposed to do that? A) I'm using a working language already. B) Read the comments on the mailing list regarding third party proposals/implementations from the Go authors. In short: Complete waste of time.
- brianolson 12y agoThe first point "no generics, no code reuse" is the best one. Go really needs generics/templates/macros or _something_. It doesn't even have subclassing, although you can kinda extend a type if you only use its public interface. I've been tempted to see if I could reasonably use the "text/template" package and feed that back into the Go compiler to achieve this. The rest is mostly a Haskell fanboy whining that Go isn't Haskell.
- NateDad 12y agoGo has a very nice standard library. The whole thing is reusable code.
- falcolas 12y agoNot every problem can be solved with the standard library. At some point you need a 3rd party library, which may require your modification to work with your data types.
- NateDad 12y agoThe point is that everyone assumes you need generics to reuse code. And that's simply not true. For some very specific problems that can be true, but in many many cases it's not. My point is not that you never need anything outside the standard library, just that the standard library does a hell of a lot and it is by definition reusable.
- theseoafs 12y agoGo's standard library uses generics a lot. In fact, Go's built-in datatypes are the only parts of the language that are allowed to use generics.
- NateDad 12y agoBuilt ins are not the same as the standard library. The standard library consists of packages written in normal go for things like networking, web servers, JSON, regular expressions, etc.
- jondubois 12y agoStatically typed languages impose unnatural hardware-oriented constraints on your business logic - It forces you to spend extra time and effort to make sure that your logic is in a format which the compiler can understand. Yes, this can sometimes help you to find silly errors in your code at compile time (and thus occasionally save you a bit of time) but, unfortunately, that occasional benefit doesn't make up for the productivity loss incurred from constantly trying to 'please the compiler'. Dynamically typed languages offer fluidity in your logic where it is needed. For example, if you add an integer and a decimal (floating point) number together, there is nothing wrong about this mathematically, but a static compiler will complain! It's a limitation of the compiler not the programmer! Statically typed languages force you to implement rigid class/type schemas within your logic (sometimes with complex hierarchies) - These schemas have to be significantly reworked whenever your business requirements change.
- muraiki 12y agoI'm not trying to be insulting, but did you read the article? From what you've written, it sounds like you haven't actually used an expressive type system. For instance, in Haskell I can type 2 + 3.75 and I get 5.75 right back -- no errors. That's because the type signature of + is "Num a => a -> a -> a," meaning I can add two of any type of Number (Integers and Floats are both Numbers, of course).
- ufo 12y agoActually, I see having to rework the type schema when the requirements change as a plus, not as a con. In a static language the compiler can point out all the bits of the program that need to be updated to conform to the new schema while in a dynamic language this kind of stuff is usually only detected at runtime.
- theseoafs 12y agoHave you never used a statically-typed language? Most statically typed languages can handle adding an integer and a float together. The only one I can think of that isn't capable of that is OCaml, though this is probably a strength of OCaml rather than a weakness (int-to-float casting can be a common source of bugs if it happens unexpectedly).
- zachgersh 12y agoWanted to say, you can potentially do better than this in go for arbitrary JSON: type JSON map[string]interface{} Go ahead and use the json.RawMessage type instead: http://golang.org/pkg/encoding/json/#RawMessage http://golang.org/pkg/encoding/json/#RawMessage Not even going to wade into the lack of generics war, still very happy without them and going on a full year of Go usage.
- chimeracoder 12y agoYeah, I almost never use map[string]interface{} when unmarshalling JSON. Most JSON has a static structure (and I'd argue that any JSON that doesn't is misbehaving). If the structure is static, you can simply use a struct that represents this[0]. If it doesn't, then you just use json.RawMessage to defer unmarshalling, but you can still dispatch to a finite number of structs that represent the universe of possible responses. [0] And no need to write it all out by hand - if you have a single example JSON response, you can generate it automatically: https://github.com/ChimeraCoder/gojson https://github.com/ChimeraCoder/gojson
- _jp__ 12y agoI loved VB6 so i like go really much...
- callesgg 12y agoHow can sort be considered generic. Every type must be sorted by different stuff, the compiler can't possibly know what that stuff is. I see what the author is coming from but generics would break what makes go great. There has been times when I wanted generics, but it has generally meant that i was looking at the wrong side of the problem.
- lmm 12y ago> How can sort be considered generic. Every type must be sorted by different stuff, the compiler can't possibly know what that stuff is. What. Have you even used a language with generics? Yes it can, very easily; you can do it in a traditional-OO way by having a sortable interface, or if you want to be really cool you do it with a typeclass.
- thrownaway2424 12y agoSort is generic when order is generic.
- Animats 12y agoThe article author points out, correctly, that Go code has far too much "interface{}" in it. That's an indication of real need for more power in the type system. Generics may be overkill. Parameterized types may be enough. The difference is that you have to explicitly instantiate a parameterized type. Generic functions and classes get instantiated implicitly when used, which gets complicated. (See C++'s Boost.) Go already has built-in parameterized types - "map" and "chan". Those are instantiated with "make", as with p := make(map[string]int) That's an instantiation of a parameterized type in Go. Go already has a full parameterized type mechanism. It's just that users can't define new parameterized types - all you get are "chan" and "map". For parameterized types, struct definitions would need type parameters. A parameterized type would later be instantiated explicitly in a type declaration, with the parameters filled in and a new name given to the generated type. This is more explicit and less automatic than generics. There's no automatic specialization, as in C++. This is enough that you can write, say, a binary tree library once and use it for multiple purposes. It's not enough to write C++'s Boost. That seems in keeping with the design of Go.
- tankenmate 12y agoExcellent idea. I think maybe having strict type interfaces for the implementation so you could roll your own would be a good idea too; à la perl's tie HASH => TIEHASH, FETCH, STORE, et alia, TIEARRAY, FETCHSIZE, STORESIZE, et alia, etc. Obviously then you can have slices, arrays, maps (hashes, dicts), that can be use whatever backing store / behaviour you want / need. This will mean that behaviour of individual data collections may not be as clear cut in their behaviour (skeuomorphically) but the upside is more flexibility.
- burntsushi 12y agoThat's not really the full story though. The parameterized type isn't just `map[K]V`, it's more than that. The type `K` needs to be hashable, and not all types support that. e.g., slices do not: http://play.golang.org/p/IKp_I25NW2 http://play.golang.org/p/IKp_I25NW2 It gets more complicated then that too, because composite types can be used for keys, but only if the type does not contain any non-hashable type. Similarly, if you're going to build a binary tree data structure, then you probably need a way to compare elements. How do you express that constraint? Standard ML has a similar limitation, which resulted in the presence of an `eqtype`, which is basically a way of saying, "any type T that can be compared for equality." But of course, ML has its modules... So I'd argue that type parameterization alone doesn't really buy you much. You might say: well, we need bounded polymorphism then. OK. How do you define bounds? Maybe you figure out a way to abuse interfaces (but a bound isn't a type while an interface is a type), or you add a new way of specifying interfaces to the language. The road to generics is long, complex and fraught with trade offs. Blessing a few key parametric types is a really interesting compromise, and I believe it's one that was absent in a similar practical manner in pre-generics Java and C++.
- sea6ear 12y agoThis really seems like a guy who doesn't want what Go has to offer. At every place he compares Go and Haskell, he wants Go to be like Haskell. There's already a language like that - Haskell.
- sacado2 12y agoLooks like someone else discovered Go isn't as good as Haskell to program in Haskell. It's a good, very pedagogical article, however.
- likeclockwork 12y ago"When the three of us [Thompson, Rob Pike, and Robert Griesemer] got started, it was pure research. The three of us got together and decided that we hated C++. [laughter] ... [Returning to Go,] we started off with the idea that all three of us had to be talked into every feature in the language, so there was no extraneous garbage put into the language for any reason."