Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

>When asked what changes would most improve Go, users most commonly mentioned generics, package versioning, and dependency management.

and:

>What changes would improve Go most? (first: Generics)

Number one issue mentioned.

So much for all those insisting that Go users have no issues with the missing Generics and don't miss/need them in practice.



But, also, number one liked issue: simplicity. The go team doesn't say they don't want generics, they say they haven't found a non-complicated way to implement generics.


Well, I don't think there's some magic way.

There are just the N ways PL research has found for implementing generics. Either they implement them, and tackle the complication one of those N ways entails, or they don't.

Besides, has anyone seen much experiments, with actual coding or at least design, for finding this "non-complicated" way anyway? Not just some post once in a blue moon re-iterating the basic well known tradeoffs.


>Besides, has anyone seen much experiments, with actual coding or at least design, for finding this "non-complicated" way anyway?

Proposal from Ian Lance Taylor, Go developer at Google

https://github.com/golang/proposal/blob/master/design/15292-...

View of Russ Cox, Go developer at Google

https://research.swtch.com/go2017#generics


Yeah, I've read both -- and more. None of this is what I described: either actual code, even if in some experimental compiler branch/fork, or at least a concrete design.

Ian's just reiterates the various options (Rob Pike has already written similar things), and Russ Cox is just several vague ideas for future additions to the language.


So, Russ says it is Ok to have generics but there are higher priorities. The problem with this approach is that eventually when they will add generics, there will be whole ecosystem living without them, which means this ecosystem will need to be entirely reimplemented.


Why ? It's not as if the old code needs to be rewitten just because there is the option of generics.


Yet millions of VB and C# users deal with them every day and seem to be doing fine. For a concept that's so old, it seems unlikely they're going to find some breakthrough either in implementation or language-simplicity.


Add invariant-only generic types (no subtyping relations between types with different type parameters) as a way to avoid 90% of casts. It doesn't get easier than this.

As for going further, I think covariance and contravariance, while conceptually simple, will always be too complicated to wrap your head around.

I think the future is invariant types + advanced generics functions. But research hasn't explored that direction yet. I might want to do that in the future.

If it's relevant to anyone's interest, feel free to contact me.


Not really the first.

generics = 16%

management+dependency+package+dependency management = 38%

(what a crappy survey. I'm not sure is it even possible to just sum these)


It's not possible to sum them. See the explanation of how to read the data under the "What do you like about Go?" results. In particular, "management" and "dependency" both include the "dependency management" counts, so including those in the sum double-counts responses that say "dependency management".

I ran the numbers just now, and 571 responses contain the (case-insensitive) text substring "package manage" or "dependenc", compared to 623 for substring "generic". These two topics are very clearly the top two. They're also both on my list for this year (research.swtch.com/go2017). It doesn't seem that important which one "won".

If you have suggestions for how to summarize free-response text in a way that lets the data speak rather than lend itself to cherry-picking, please let us know. I'm certainly open to improved analysis next time.


generic = 1%

generics = 16%

so it's a good chunk of the people who answered the survey.

2% mention types and 1% type system so it might be possible these come from people dissatisfied with the type system.

Finally, it's not clear whether people who mentioned dependency management where also counted in dependency and management.

All we know is that "generics" was the word the came out the most often.


The interpretation of the open questions could definitely use some semantic analysis; I agree that it really does look like there's more frustration around packaging than generics, based on how they interpreted the results.


FWIW, generics were added to Java in 2004, about 9 years after initial release.

ref: https://en.wikipedia.org/wiki/Generics_in_Java


And one could say it was too early. Under the hood, generics are pretty bad in Java [0]. Type information is mostly lost; it's a compiler time only feature. They're much better implemented in C#, even if they look the same on the surface, probably because it came later and they took it seriously.

So I applaud the Go architects with being conservative about it. More languages should take their time thinking about implementing features, no matter how needed they seem to be initially. You only get one chance, and then if it's a bad choice you live with the consequences.

[0] http://www.jprl.com/Blog/archive/development/2007/Aug-31.htm...


Just about every programming language expert I've seen who's talked about Java generics says Java did a better job than C#. In fact, of all language runtimes that do generics, the .NET runtime is the only one that specializes. Examples of runtimes that do not specialize or reify generics:

* JVM

* Haskell runtime

* ML family of languages

* Modula-3

* Ada

The problem with specialized generics in the runtime is that they bake the type system of the language into the runtime itself, making the runtime more difficult to work with. Type erasure, for instance, makes it much easier to implement alternative languages on the JVM such as JRuby, Clojure, Scala, or Kotlin, than on .NET.

As another example, C# in 4.0 added the concept of generic type variance, which is completely at odds with specialized generics. To implement this feature, the C# language designers had to modify the underlying runtime itself and add special bytecode instructions for the feature. The feature itself is also incompatible with specialized generics, so when you use it you silently lose specialization. In contrast, thanks to type erasure, the Scala language designers could easily add the same feature on top of the JVM as-is without needing Oracle to add special bytecode instructions.

Specialization has advantages for performance when doing number crunching with data structures and algorithms operating directly on integral or floating point data types. At the end of the day, though, if you really need performance for this very narrow field of use cases, you're probably not going to be using generic data structures and algorithms anyways. It takes an incredible amount of effort to build a data structure or algorithm that is both generic and also performant in all possible usage scenarios. It is however, much easier to build a data structure or algorithm that is specific and performant relative to your use case alone.

Case in point: when I was in college doing a NLP assignment that needed to be fast, my data structures were arrays of doubles because that was the easiest way to reason about and ensure performance.


> In fact, of all language runtimes that do generics, the .NET runtime is the only one that specializes.

As a C++ programmer I would mention templates as something similar.

> The problem with specialized generics in the runtime is that they bake the type system of the language into the runtime itself, making the runtime more difficult to work with.

When inheritance comes in to play Java ends up storing generic type information in the child classes. It even has to generate bridge methods since Runtime does not really deal with int compareTo( Comparable<? extends T> ) vs. int compareTo ( MyInteger ) .

> if you really need performance for this very narrow field of use cases, you're probably not going to be using generic data structures and algorithms anyways

An ArrayList<Integer> makes sense in very few cases and is extremely slow, 64 bit pointers to objects that contain useless metadata and a immutable 32 bit int. Sadly an IntList is neither generic nor is it compatible with anything that operates on List<T>s, which results in duplication of a lot of algorithms just to sort primitives.

> when I was in college doing a NLP assignment that needed to be fast, my data structures were arrays of doubles because that was the easiest way to reason about and ensure performance.

Case in point: In C++ std::vector<double> and the standard algorithm header take care of most of that. If there is some specialized implementation of some algorithm for double values then you can still use that without copy pasting the implementation of everything else.


I purposely left out templates because I do not consider them to be the same as generics. Their is no "runtime" support for templates; templates are basically a glorified macro engine for creating new code based on type parameters. But yes, templates by definition specialize since they are creating new code every time they are instantiated.


> Their is no "runtime" support for templates;

At runtime any Java List is a list of Objects, you cannot distinguish an ArrayList<Integer> from an ArrayList<Double> both are a raw ArrayList. What runtime support do they have?

> I feel bad for the C++ linkers that have to sift through all the template bloat to dedupe them :(.

If you have a template used often enough you can declare it extern and force instanciation in a specific cpp file.


There actually is some basic runtime support for generics, just enough to avoid breaking the runtime. For instance, if I create a class MyList extends ArrayList<Double>, there actually is some runtime information that says MyList is an ArrayList<Double>, not just an ArrayList.

You're right though that saying templates are different from generics is based on opinion, not fact. There's no widely-accepted definition of both that would separate them as distinct from one another.


Generics just bake a little bit more into the runtime; there's already a lot of the type system there. And it increases interop potential. I don't understand your point about Scala - they could always choose to use type erasure instead of any runtime-provided generics. F# implemented generics with erasure on the 1.x CLR, and used the runtime when on CLR 2.

And this is the first time I've heard that the JVM is easier to target for non-Java languages. .NET has had multi-language support an official design goal, the JVM is just for Java. Even simple stuff like pointers, so you can do ref/out parameters. Or unverified instructions. The CLR is simply more all-around capable.

I am pretty sure the CLR always supported variance, it was just unused up until C# 4.0. AFAIK, there haven't been any changes to the runtime bytecode since CLR 2.0, when generics were added.

The performance benefits of specialization are pretty nifty. The Mono guys ported Android to C# and got quite the performance improvement on some code: https://blog.xamarin.com/android-in-c-sharp/ - so that's existing code that got a perf benefit "for free" due to not using type erasure.

Edit: A quick skim of the specialization proposal for Java[1] makes no mention of other languages. Just the general pain of integrating it in a compatible way.

1: http://cr.openjdk.java.net/~briangoetz/valhalla/specializati...


Brian Goetz sometimes refers to it on his presentations.

As for multi-language support on the CLR, compared with the old 1.x days, there seems to be less focus on it.

With C# getting most of the focus, followed by VB.NET and F# playing catchup.

Also outside MSR, most researchers focus on the JVM, in spite of its caveats, and nowadays LLVM as well.

ETHZ is the only one I am aware that also designs languages with CLR in mind. The Active Oberon successors, like Zonnon.

There are some companies selling compilers for .NET, like Cobol, Eiffel and Pascal. Not sure how well they are doing it.

Clojure also targets the CLR, but they don't seem to have a story for .NET Core.


Isn't that more a function of MS's hostility to other platforms, not technical reasons? If MS had been more open and friendly 15 years ago things might be different.


I don't see that as hostility, rather political decisions, including on Microsoft's own languages, with the usual issues between language departments.

For example, if everyone played the ball into the same direction, probably Longhorn could have been what UWP is becoming.


>And this is the first time I've heard that the JVM is easier to target for non-Java languages

https://www.google.com/webhp?sourceid=chrome-instant&ion=1&e...

Here's a post from a JRuby developer saying he prefers a simpler VM.

In the comments section of the same post you'll see Martin Odersky, creator of Scala, saying he also prefers a simpler VM. I could probably find more examples if I dug further.

>I am pretty sure the CLR always supported variance, it was just unused up until C# 4.0

Nope. They were introduced to both the CLR and the C# language in 4.0. See https://www.codeproject.com/articles/72467/c-4-0-covariance-... https://blogs.msdn.microsoft.com/rmbyers/2005/02/17/generic-...


I can't speak about any of the programming language experts you've seen, but:

> To implement this feature, the C# language designers had to modify the underlying runtime itself and add special bytecode instructions for the feature

I think this argument is misconstrued. This is inherent to the way the CLR was designed. It is not meant to be something that is kept as-is in terms of the bytecode it accepts. It is constantly being improved upon. Most new language features to C#, F#, or other CLR languages mean an update to the CLR if they're related to a new feature in the abstract.

While there's an argument to be made on whether this better than a more generic runtime, the point is that requiring a change to the CLR is not a big deal; that's part of their plan.


It should be plain to see that it would be much easier to implement your programming language on top of the CLR or JVM if you didn't need to request new features from Oracle or Microsoft to be added to the runtime.

I remember one time someone proposed a patch to the JVM to add tail cail optimization and it was basically rejected or deprioritized into oblivion: http://mail.openjdk.java.net/pipermail/mlvm-dev/2010-October...

These VMs are complicated machines and Oracle/Microsoft aren't going to risk modifying them unless it fits their respective agendas.


Which is why I've been very happy to see .Net Core take the path it has... it's been much more open to outside collaboration even if the bulk is done by MS employees.


Ada is compiler specific.


It doesn't appear we are waiting longer to get a better solution, rather we appear to be waiting and getting no solution.


Telling those two apart reliably is one of the fundamental problems in computer science.


Wasn't it too late? I thought the reason they went the type erasure path was because they didn't want to take the compat hit of changing the bytecode that much. Is that not accurate? Maybe if they had done generics originally it'd have been built in to the runtime. Isn't this potentially going to happen in Java10 or something?


So? Java doesn't have channels either (except in third party libs added much later), but they were in Go from the start. Same for e.g. plain structs, which Java will only now acquire.

When one language added a feature has no bearing to when another should add it.


> So? Java doesn't have channels either (except in third party libs added much later), but they were in Go from the start.

Channels is specific concurrency paradigm. Java utilizes others, not less powerful.


Since they were tacked on they also have all sorts of issues like type erasure and the like that make them a pain to use in certain cases.


FWIW Go is almost 8 years old now, and there is absolutely no plan to implement generics in anyway right now. I think they just can't without breaking backward and forward compatibility, they should just admit it instead of trying to avoid the question.


I'm a Go user, both at work and at home. My most-wanted feature is Generics, but I trust the Go core team when they say they want to ensure the feature is implemented correctly. The absolute last thing I want is for them to rush some half-assed implementation, which becomes semi-permanent because they can't fix it without breaking everyone's code.


Coding without generics turns out to have many advantages. Mostly code bases that need to evolve rapidly without getting locked in to abstractions that don't fit anymore. It certainly is a mindset shift, and may be better at scale, but it's also more tedious and sometimes you just want a freaking Foo<Bar>.


I don't really see that. How does coding IntList and then StringList help you evolve more freely than List<Int> and List<String>?

(Honest question ... I'm interested to hear what you have in mind.)


>Coding without generics turns out to have many advantages. Mostly code bases that need to evolve rapidly without getting locked in to abstractions that don't fit anymore.

How would Generics restrict you any more than the numerous variations on the same functions for different types (that you need today)?

Except if the alternative is using interface{} for everything, in which case, yes, Generics would be more restrictive.


Generics would make go code safer, less reliant on complicated tricks to circumvent language limitations and the need for reflection and ultimately make programs less brittle since it would reduce the amount of code needed for a task in general. The only valid argument against them is compilation speed but it hasn't been tried in real.


Even the compilation speed is not a problem related to generics themself, it's a problem related to monomorphisation.

If you keep dynamic dispatch, you pay almost no compilation penalty.


I'm not a Go programmer as I like my languages baroque, overcomplicated and with ridiculously overpowered generic systems [1], but there value in simplicity and maybe a macro system would be a better fit for go than fully featured generics.

[1] yes, I'm a C++ programmer


> yes, I'm a C++ programmer

If you are a C++ programmer then you know that the latest features that were added aim at making C++ programming simpler and easier. Adding something to a language to fix its flaws is not necessarily adding some complexity.


Sure, but the C++ design philosophy is to be the Swiss army chainsaw: it offers tools (often dangerous) for every need.

Go is designed to be a much simpler tool, with the spirit that constraints are liberating.

A simple macro system would maybe fit better the second philosophy than a significantly more complex type system.


That they already have in the form of Go generate, although it brings me memories from MS-DOS Borland C++ before they implemented templates and used preprocessor macros.


A quick look shows that 'go generate' simply allows filtering a file through an external tool. This is a powerful feature but has great setup overhead. Something slightly more integrated with the language (as a distinct compiler pass but still part of the language), with the capability of defining macros inline (and being exportable), and AST based instead of string based would be better.


You can combine it with the AST and template packages, getting half-way there.

In any case, I agree with you, but given the Go's culture I guess that is the closer we will ever get to compile time code generation.


Reading and writing CPP macros is awful, but it's still not as bad as reading and writing the mind-numbing boilerplate that they replace.


16% want generics and 17% love simplicity.

So much for all those who claim generics remain overwhelming concern for Go developers.


Users always like simplicity in everything. They want a big red button that does what they need. Which is why asking them about design is generally useless. They would choose simplicity every time.

There are, of course, some users, that can make substantial comments about design, but they cannot be represented in a survey.


so 84% don't want generics, right? :) I switched to Go from Python several years ago, I admit that I missed generics for the first several weeks but then just moved forward. Nowadays I don't really think I actually need them anymore.


Well, it's not like you had them in Python anyway, so there was not much to miss.


Generics are a mechanism by which a statically-typed language can approach the generality of abstraction possible in a dynamically typed language while preserving static type safety, so even though Python doesn't have generics, one absolutely would have good cause to miss them going from Python to Go.


>so even though Python doesn't have generics, one absolutely would have good cause to miss them going from Python to Go.

Not really, since you can always just use interface{} for everything and get all the dynamism back.

Generics is when you want to have both (dynamism and safety).


Actually 31% likes its simplicity (4th rank is simple, 14%).

Other similar answers:

2% easy to learn, 2% simple syntax, 2% simple language, 1% easy to use, 1% easy to write, 1% ease of use

In the case of generics there's another 1% answer on generic


Why not fork?


Go++ should at least be an April 1st thing, since it is coming up.


It should add everything C++ has or would that go2far ?


Because everyone of us that cares about generics uses languages that support them, and most likely a Go++ effort would be in vain, after all there are already a few Go preprocessors, which don't seem to be widely adopted.


Also, are generics really the only way to go?

I mean, parametric polymorphism is achievable with different approaches...


And maintain type safety?


Maybe algebraic data types would be more suitable.

In Go, you don't have subclassing, so you cannot implement YourClass<T extends SomeAncestor>.


> Maybe algebraic data types would be more suitable.

There is no opposition between ADT and generics. In fact most language that have ADT have generics…

> In Go, you don't have subclassing, so you cannot implement YourClass<T extends SomeAncestor>.

There is no link between generics and inheritence, functionnal languages usually don't have OOP mechanism but they still have generics.


Take a look at CLOS. It's for a dynamically-typed language, but the same principles could be used to provide for multi-methods in a statically-type language like Go.


With what money and whom to maintain the fork? The survey even shows that most go users never or rarely contribute the any open source go project (25% + 34% respectively). You'd need a solid corporate backing.


Because I don't have Google's money to support it.


Why fork? To depend on Go? Compile into Go instead.


I have repeatedly thought about building a variant of Go that compiles down to Go and then gets compiled by the upstream compiler, mostly to add generics and autogenerate all these

  if err != nil {
    return nil, err
  }
blocks. But it would most definitely be a pain in the ass to integrate this with the toolchain.


You really think a fork will help here? Can you explain a bit more how do you think a fork will work out?


So one side has its Go with generics and one without and in the end we would see which would do better?


why not both?


yes, why not?


What I think is a bit remarkable is that it's not so much generics which are lacking, but syntactic abstraction. Folks focus on generics, but really the one thing Go is missing is the ability to extend the language as a programmer.




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

Search: