Go generics may use square brackets [] not parenthesis ()
groups.google.com
groups.google.com
https://www.reddit.com/r/rust/comments/5penft/parallelizing_...
> If you look closely, those aren't angle brackets, they're characters from the Canadian Aboriginal Syllabics block, which are allowed in Go identifiers. From Go's perspective, that's just one long identifier.
And the next comment is the same thing everyone else is thinking: “oh my god”
Gives new meaning to the phrase "Native apps"From Go's perspective, that's just one long identifier.
The designer was using those characters to trick the Go compiler which I then suspect means things like go format would also continue to work.
Then the designer could easily create a pre-processor that translates those placeholders characters as a way of providing some sort of generics in Go.
So in reality this was quite a good solution as I can imagine coming up with a solution that broke go format would have been a real pain to use.
Yes, I do not understand why people find this so hilarious. It's a clever choice.
Here is __REPLACE__ var.A wise choice would be simply adding double underscores between the identifiers.
> c++ allows 0-width spaces in variable names. Where's your god now?
I imagine many languages do the same, but I lack the will to test it.
Anyway, of course, it would be more correct if it was considered whitespace... And I bet anything parsed in Haskell or Perl6 does such.
To quote my favorite mathematician specializing in chaos theory, ”Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.“
Old-style link: https://old.reddit.com/r/rust/comments/5penft/parallelizing_...
Actually my biggest complaint is the lack of ability to maximize comments - basically, I detest having to click n times just to be able to read the whole discussion. There's a bit of content, and mostly SPAM on that page. Old design was mostly content.
> Why not use F«T»?
> We considered it but we couldn't bring ourselves to require non-ASCII.
"falsehoods programmers believe about keyboards"
On the keyboard layouts of many countries these keys aren't accessible at all, either missing entirely or only being accessible via unergonomic key combinations.
For this reason myself (and many other programmers) own additional ANSI-US layout keyboards.
I'm afraid there's no easy solution to this problem but I'd like to hear your suggestion.
begin
and end
Isn't there? ;)It may be, that in the end the parens are the solution to use, but at least it should be considered in the discusion, that they are not very easy to use for a lot of non-English layouts. Just assuming anyone in the world would use an English layout, is quite offensive in my eyes.
I never felt like owning a new keyboard was necessary as a memorized the keys fairly quickly. The CA-FR layout is QWERTY+accents, but () {} etc. are weirdly placed, some requiring the use of the “alt-car” key which I’m not even sure exists in the US layout. I really hate programming or using vim in that layout.
Are there layouts where that approach isn’t feasible? Or is it mostly a memorization issue?
You can adapt most of the western layouts to at least get "[]{}" in easily accessible places, but for instance trying to adapt a German layout can get really confusing. Have a look at this typical German layout:
https://upload.wikimedia.org/wikipedia/commons/thumb/3/36/KB...
So we can remap "{}[]" to somewhere next to the enter key, ideally by moving the "+" key to the upper row. We also want to remap "|" and probably "<>" somewhere next to the enter key, because typing those a lot also gets awkward in their former spot. You could compensate by the entire bottom letter row to the left, arriving at something close to US-ANSI.
Needless to say, that's going to get really confusing. I'm a touch typist, but if I'd already have trouble, I don't want to imagine what that's going to be like for someone who is not.
Personally I just use an ANSI-US layout keyboard with a few custom shortcuts for typing ä, ö and ü. I can get away with this because I don't need to write a lot of German text.
For someone who has to switch between layouts to be efficient in both writing German text and code, it's probably better to use physically different keyboards so it's easier to build muscle memory.
Except on a mac, because for some reason the mac layout is totally different, which is why I need to use a key remapper on my work computer.
You can write the characters using digraphs.
For example, type <"> and then <a> to get <ä>. Type <"> and then <space> to get <">.
This won't work for other alphabets, of course.
Not sure what CJKV users do.
Chinese: the physical layout is always ANSI US. Depending on the IME you might want more than roman characters printed on keycaps, but it's just cosmetic if you can touch-type.
Japanese: most keyboards use the JIS layout and visually support multiple IME, but if you stick to romaji, using an ANSI US keyboard works too.
Korean: the physical layout is ANSI US (sometimes with 2 extra modifiers). Hangul is a proper alphabet, symbols are made up of subcomponents (jamo) that are printed on the keys. Again it's just cosmetic.
In my experience, people of my generation (30-40 years old) who are educated know to touch-type. For instance I've never met a Taiwanese that needed to look at the Zhuyin symbols on a keyboard.
But I've heard that's not the case anymore with kids that grew up using smartphones.
What I like about using US Intl (I've modified it slightly) is that no switching is required, I can conveniently enter both the programming related characters (such as curly braces which require gymnastics with a German keyboard layout) and the German specific characters such as umlauts.
But I can't imagine that this could be possible for Chinese without switching modes (or input methods or keyboar layouts).
Everywhere else, it's reasonable to assume that if you're a programmer, you speak English and likely have an English keyboard. This may not be fair, but it is the state of affairs.
You likely own a US keyboard not only for the parentheses problem, but because of all sorts of English isms throughout all code -- alphanumerics, urls, etc are all in Latin script. It's like German in the field of mathematics in the 19th century.
Yes, they are symbols that are used in many programming languages. No, it's not reasonable to assume that they are easy to type for all of us.
Anybody who deviates from that is doing so at their own risk. If you want to use Dvorak or Azerty instead of Qwerty then you can do that, it's just not advisable because things like Vim will no longer make sense.
If you try to write code using a layout that doesn't have all the ascii printable symbol characters in accessible locations then you're creating a special kind of hell for yourself. It takes like 30 seconds to change to US layout.
That’s not reasonable at all. You have way more people writing code outside of the US than within. The US layout may be the most represented one, I don’t know statistics on this, but I would expect it to be on the losing side when comparing US layout vs non-US layout.
Though I would agree that having access to ASCII is something you need, but any standardized keyboard layout in the world can do that via modifiers, if not directly.
The only alternatives would be to converge on a lowest common demoninator, and have a likely more inconvenient syntax for all parties, or to diverge into regional-specific dialects, which unicode shows to be.. wide.. and generally make code sharing much harder.
This is really more of a "many mostly equivalent solutions, but one needs to be picked" scenario -- and it would be time poorly spent trying to undo the incumbent solution (and will naturally be rendered untenable by endless bike-shedding anyways). The worst of all solutions -- except for all the others
Using a German layout is very much a choice you have made and is no reason for you to demand that programming languages should make everyone else's life harder to acomodate those choices. Even for German text input, umlauts and sz are rare enough that it is not much of a hindrance to have to enter those via dead keys or compose sequences on a layout that doesn't make {} and [] a pain to type.
I really don't think most people use the American layout. That's just typical america-centric narcissism.
External keyboards, sure. But many of us are laptop-only.
Sure, you can remap the keys, but also, not everyone is a touch typist.
Curly brackets etc use hand-twisting alt-gr combinations on a Swedish layout so I’d be better off using a US keyboard mapping so I can type ([{ using only shift. I have tried and failed to make that switch. It would probably just slow me down for a month or so before it made me faster, but I’ll keep pushing my square-wheeled cart thank you.
There's no English keyboard.
Writing French with the US international layout is actually pretty easy.
The umlaut is a dead key so it's very easy. ß is AltGr or Option + S which I admit is a bit more annoying, but your spellchecker should take care of that, no? (I'm Swiss so even when I have to type in broken German, we don't use the ß here).
All layouts are tradeoffs. Not using the US layout makes a lot of things annoying in our field. I write code and use my IDE's keyboard shortcuts more than I need to write long texts in my native language.
So " is Shift+' and @ is shift+2
In UK keyboard layout, @ is shift+', and " is shift+2 (which is what is shown on my keyboard keys).
I've switched to US intl 15 years ago and I don't type in French any slower than I used to. On the other hand I benefit greatly from using the default layout in our very US-centric field.
My favorite keyboard is British up to the point of me specifically picking a laptop/physical keyboard with a British layout.
Just learn both and you'll be OK.
The thing with touch-typing is that you don't think so you have to go through a period of discomfort.
Edit: If that wasn't clear, I meant that I touch-type on both layouts quite easily.
Not really relevant, as we're talking about keyboards and setups used by programmers.
If they don't know how to change the layout in English to program, then perhaps they're not fit for the job.
(Non ASCII/US programmer here).
The shifted semi-colon must be irritating in C-like languages, but even on US/UK keyboards, characters like ( and { need Shift, which admittedly is larger than Alt-Gr and there are two of them.
I wonder if the larger right Shift key can be mapped as Alt-Gr.
PS. Does Icelandic need the letter 'mu' often enough to dedicate a key to it on the keyboard?
[1] https://en.wikipedia.org/wiki/Icelandic_keyboard_layout#/med...
It's mapped to Alt-Gr+M on Swedish keyboards as well, but I've never seen a keyboard where it's actually written on out on the key.
I'm sorry, but what?
Most people who use the metric system can't tell you which is smaller: micro or milli. Most people will never encounter anything in their lifetime they will actually need to reason about in some important manner that is measured in μ-anything.
As a user of the Icelandic layout I wasn't even aware that the key was on there, but I can confirm that we absolutely don't need it. I think there are probably a lot of keyboard layouts that could use modernizing wrt. how they are actually used today.
That doesn't seem unreasonable, when we have <, >, { and } for mathematics, \ originally for logicians (to combine to make /\ AND and \/ OR) and |, @, _ and # for programming.
shift + 8 -> (
shift + 9 -> )
alt + ctrl + 8 -> [
alt + ctrl + 9 -> ]
alt + ctrl + 7 -> {
alt + ctrl + 0 -> }
Alternatively alt + ctrl can be replaced by altgr.
And for further fun:
alt + ctrl + ß -> \
shift + 0 -> =
shift + 7 -> /
Actually, it is probably easier to link the whole layout: https://de.wikipedia.org/wiki/DIN_2137#/media/Datei:Deutsche...
It is pretty bad for programming in languages that make heavy usage of braces/brackets/parenthesis.
[1]: Decided one day to get myself one of those little booklets with training software on CD. I then slowly stepped through the training steps (each step more letters and more repitition of already learned ones) and got decent at touch-typing by forcing myself to use it more and more in everyday uni life. Took about one or two months to get up to a level usable in general typing (writing for reports/homework AND programming) with little to no pauses or errors.
And without correct keycaps it is even harder.
Of course you'll have to fight your muscle memory and type at 20 wpm for a couple weeks. There's no shortcut.
That forced me to always touch type, a good thing. It also has the advantage that the layout is pretty consistent across physical keyboard layout.
That's not the case for UK Qwerty; UK Apple is different to UK ISO is different (obviously) to ANSI. Where as Colemak is pretty consistent. So it's been helpful when moving between machines and OSs.
...it's also been the generator of hilarious memories, such as when someone changes their layout to Colemak for me to type something and then we logout their machine and discover they can't type their password or change layout back to Qwerty. Ah, good times...
The thread is about the accessibility of some brackets on German QWERTZ keyboard layouts. These curly brackets aren’t even printed on some external Apple keyboards. And if you try to type them with one hand, you would need to turn your wrist in some unnatural position. That’s the main reason why I use an US QWERTY keyboard for the last 15 years.
I only buy ANSI keyboards and like the layout better (both Enter and left Shift are easier to reach) but I occasionally get to type on ISO keyboards, it's not too bad.
But in a general sense, I fully agree to your statement. Learning to touch type was an extremely valuable skill to acquire and I can only recommend it to everyone.
I have
* <shift>+<8,9> for (,)
* <altgr>+<è> for [
* <altgr>+<+> for ]
* <altgr>+<shift>+<è> for }
* <altgr>+<shift>+<+> for }
yes, it's a pain to use some languages.
Also, random rant, the IT keyboard layout is moronic because on most platforms inputting accented uppercase letters is not possible in any way. Ironically, 'c with cedilla', section sign `§`, degree sign and the now unused pound sign are present on every key and easily typed using shift.
I've been arguing since the dawn of time that "US with dead keys" is a vastly better keyboard layout for Italian than the Italian one, and that's the one I use (more correctly, I use US International with AltGr keys due to the fact I type accented letters less frequently than I type single quotes or backticks).
What operating system are you on? I can only create those with AltGr, anything shift-alt will be interpreted as a keyboard shortcut.
Are you maybe confusing alt ctrl with alt shift? Your comment seems to indicate it as that being the case.
* On Linux: ``example`
* On Windows: ``<left>example
Some editors even turn the latter into ```` when I double press the backtick as no symbol renders prior to that.
if none is available for your language you can build it yourself: https://zauner.nllk.net/post/0014-windows-no-dead-keys/
Btw, Microsoft Keyboard Layout Creator is a terrific tool. I spent around 10 minutes sω tφαθ İ cöüλδ tyπε lıκε δiş. (Turkish characters accessible through AltGr and Greek characters accessible through a dead key) And if you look at the config files (some kind of tab separated values with comments), the created keyboards are easily sharable and combinable.
Why though when you can change layouts without changing keyboards.
The main one is that you might not know the placement of the keys of the US layout by heart so having your printed keyboard match the layout is best. I'm a touch typist, but I still look from time to time to find things like | or ~.
Also, your physical layout might be slightly different, then finding the right key becomes a matter of trial and error for some edge cases (think the inverted L shaped enter key vs the long rectangle version).
There really is no reason to switch between actual physical keyboards to use a different keyboard layout, even if you need to look at the keys(and it would still require you to switch layouts in software). Surely googling a layout cheat sheet is easier than switching keyboards.
In my case, more than switching, it's that my laptop has a spanish set (work provided), and I went through the trouble of buying an external one with an English layout. It's not like I'm switching between them every few minutes, the Spanish one is left unused. I don't even bother switching layouts, since I can perfectly write Spanish with the English layout (the only missing keys are accents, which I omit in informal texts, and the ñ key that I can get long pressing the n).
I could use the Spanish one and look at a cheat sheet from time to time, but it's inconvenient enough that the 40 extra bucks feel like a good inversion.
Writing the below in other languages (pseudocode) feels repetitive in the same way that `Thing thing = new Thing()` did back before `var` or `auto` types became popular:
list<Y> Map<X, Y>(list<X> inputs, X->Y mapping)
Why do I need to put <X, Y> in brackets after Map? To tell the compiler that these are generics, not attempts to reference actual specific types that just happen to have crappy, nondescript names like X and Y.In F# and friends, there is no need to put a bracketed block declaring which types are generic parameters. I would simply write:
let map (inputs: list<'x>) (mapping: 'x -> 'y) : list<'y> = ...
The little apostrophe or tick mark before the type name tells the compiler it's a generic type parameter. It's not legal to name a concrete type with a leading tick mark, so there can be no mix-up. At first it looks ugly, but once you are used to it, it is natural and less cluttered than having to have these separate bracketed declarations for "uh-oh, here comes a generic".But I suspect Go will always want more explicit syntax for generics. In part out of backwards compatibility, but largely because Go's designers see generics as an advanced, occasionally useful feature. Correspondingly they'll want the presence of a generic function to have ugly syntactical warning signs: here be dragons.
Functional languages usually take the opposite approach and see a fully generic function as less complex than one for a specific type, because just by looking at its signature, you know it doesn't require anything special about the input objects it's going to work on. It is not going to be calling methods on them or messing with their guts. It's just treating them as black-box, could-be-anything cards to be shuffled around from point A to point B.
Make identifiers that start with period or tilde perhaps be used for template vars. And only template vars. Might be a bit noisy but less noisy than reusing various types of braces.
Not sure if .a or ~a are good choices. The latter is especially bad since it clashes with common syntax for "(bitwise) not a".
Try:
let foo (arg: list<'x>) : list<'x> =
...
<inside foo somewhere>
let bar (arg: list<'x>) : list<'x> = ...
...
Is bar generic over a fresh type that happens to be named 'x, or is it a monomorphicly-typed local function that uses the type 'x that foo is generic over? List<X> foo(List<'X> inp) =
...
List<X> bar(List<'X> xs) = ... # new X scoped to this declaration
List<X> baz(List<X> xs) = ... # use foo's X
...Best, of course, would be some middle ground assisted by a fantastic compiler.
group_by : list[`a] -> (`a -> (`b : hashable)) -> Map[`b, list[`a]]
or somethingin haskell:
noConstraint :: List a -> (a -> b) -> List b
withConstraints :: (Hashable a, Frobable b) => List a -> (a -> b) -> List b
you still don't have to declare `a` and `b`, you're just adding a constraint on them.(iirc in haskell types have to start with an uppercase character, which means you can use lowercase letters for type variables without extra apostrophes etc)
There is a difference between becoming C++ and allowing programmers to make fundamental abstractions without interface{} hacks.
All these things were already pointed out 10 years ago and were met by "you don't need that with Go", "Go back writing Java" sort of contempt, which gave the Go community a bad reputation.
Go could have been fixed 10 years ago if Rob Pike and co listened. They didn't want to because they thought they knew better than everybody else. ADA already fixed the genericity problem while keeping things readable with a limited form of generics as incomplete types.
Something that they acknowledged not bothered to look at initially.
https://go.googlesource.com/proposal/+/master/design/go2draf...
> We would have been well-served to spend more time with CLU and C++ concepts earlier.
A typical NORTH AMERICAN computer keyboard.
Does the myopia of the Go compiler team know any bounds?
Ironic that you are criticising them for only thinking of the US, but you've done exactly the same thing.
I wonder if there is more of people like me or people like you...
Don't worry, no is productive in something like c
> After being stuck with a succession of scripting languages that weren't doing it for me
I am saddened yet also consoled everyone that likes Go comes from the scripting languages. That's such a low bar to beat!
How many languages are there released by advertising companies?
Just to show the influence, python was an obscure programming language until Google started using it.
But Python has had many interesting sponsors throughout the years, not only Google.
The political wars at Google with Dart are quite visible from outside, with Fuchsia picking up Flutter, and strangely the future of Android UI looks pretty much like Flutter, after too many times asking Android team about what was their opinion on Flutter for Android development at IO Fireside, meanwhile the developers' survey has had questions about how much we cared to see it supported on Kotlin multi-platform.
So yeah, had Chrome decided to push Chromium VM no matter what, Dart would be as successful as Go by now, after all younger generations don't seem to have any problem being Chrome developers.
1. Elixir: Pros: Erlang threading model is clearly the best I've come across, expressive syntax, strong data structures and algorithms in standard library. Cons: Slow for some things, anemic standard library for common problem domains, small community.
2. Python: Pros: Strong standard library for common problem domains, supplemented by a strong community set of libraries. Generally intuitive. Cons: Slow for some things, poor threading, inconsistencies in syntax, general dominance of configuration-oriented programming frameworks rather than libraries in the community, types are just not quite strong enough.
3. C#: Pros: strong type system, speed. Cons: dependency injection hell, MS walled garden.
I'd like to add Rust and/or OCaml, to this list, but I don't know either well enough to be confident.
.NET Core is FOSS though?
My guess is that MS proprietary tooling still sucks out the air from FOSS tools, but I can't speak from experience there so I'll just admit I don't know how the ecosystem has changed since I worked in it.
It's nearly impossible to find out which of the umpteen repositories contains the source for the class you're trying to understand, and MSDN won't be of much help. Much of the standard library also has a bunch of decoy source files that only contain signatures and/or mocks, so it's a pain to find the real version.
OmniSharp has a "go-to-source" option, but you only get the real source if it's in the same solution. Otherwise you only get signatures. Try giving Metals[0] or Rust-Analyzer[1] a shot, this stuff is night-and-day.
The official debugger (vsdbg) only works in VS and VSCode (and explicitly not in FOSS builds of VSCode). There is netcoredbg[2], but I still haven't figured out how to convince Emacs to use it. This wouldn't be as much of a problem if the culture wasn't so hostile to printf debugging (for example, ~nobody bothers to implement helpful ToStrings).
There is a heavy cultural bias towards MS libraries, regardless of their merits (ASP.Net Core, DI hell, EFCore, etc). See [3] for an.. interesting example.
OmniSharp has a habit of giving up randomly, giving useless error messages, and most GH issues consist of people repeating "+1", until there is a one-liner about how an update fixed it. Root cause analysis, what's that?
[0]: https://scalameta.org/metals/
[1]: https://rust-analyzer.github.io/
[2]: https://github.com/Samsung/netcoredbg
[3]: https://old.reddit.com/r/csharp/comments/9kha39/does_anybody...
I have to admit I almost never run into this issue because because I don't really care what the source of the standard library does, the docs have always been sufficient for me. You could try https://source.dot.net/ though.
In the very rare case I do want to see the source of some 3rd party code I use dnSpy. It isn't as nicely integrated, but it's a very nice decompiler and debugger.
I say this as someone that doesn't use it for similar reasons as you. But I have ran into the above trap before.
if let var_name = nullable_var {
// use var_name as non nullable
} else {
// nullable_var in null, handle null case
}
And any tagged union can be reduced to nullable of member type without pattern matching, with some specific syntax. It is not hard with an imperative language.2) Without generics, you are probably reinventing the same code, or using reflection which is not even type safe, or worse, using code generation. For instance D has generics AND good compile times. I guess Nim compiles fairly well too. Or you can choose partially type erasure based generics with a different tradeoff. There is no point in not having useful generic functions on generic data structures in a language that came in 2000s.
Once write Python or ruby or something and come back to Go. People without knowledge of other languages with generics tend to think you are writing for loop in while loop in if - else break monstrosity because native compilation and performance come with a cost in expressiveness, while it need not be.
The C# 8.0 approach to non-nullability doesn't require generics at all (though C# already has a robust generic system). They just made reference types work the same as value types, add a ? if you want it nullable, otherwise it isn't.
I think Rust's way of doing it with Option is probably a better way, but C#'s way of doing it is definitely more accessible to the average programmer.
> Non-nullability requires generics for a result type which is a huge source of complexity.
Option could be another built-in generic like Map in Go. Or one could simply have to write a new Option type ever time. Sucks, but aren't go programmers used to this sort of thing?
> Generics impacts runtime efficiency.
False
They used that time to carefully evaluate the utility and ethos compatibility of generics. And they're taking time thoughtfully implementing them.
This is what you want out of a language. Thoughtful design and responsiveness.
The switch from parentheses to square brackets is just the first step toward that admission.
The resistance of C's design adopting anything that was already considered good practices in designing secure OSes outside Bell Labs, has a very familiar feeling.
"A consequence of this principle [of security] is that every occurrence of every subscript of every subscripted variable was on every occasion checked at run time against both the upper and the lower declared bounds of the array. Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to -- they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980, language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law."
Until this kind of issue start suffering lawsuits, most companies won't change their behaviour.
Look at Microsoft, all the security speech, C++ Core Guidelines, improving .NET for low level programming, new founded Rust love, yet the Azure Sphere team decided to use C on what is supposed to be the Fort Knox of IoT security. A bit though story to buy. I imagine the Phonon layer has probably hardware memory tagging, but they aren't revealing what it does.
Some generic obsessed people talking about generics is neither everything nor everyone.
And a big share of users wishes they add generics - judging from it being the #1 voted feature in the annual Golang polls.
Not to mention the potential users that are put off because it doesn't have Generics...
Generics is mainly for users who have committed to Go and new productive language features could possibly help them.
If I'm forced to use a language, it might as well have Generics than not...
In the context of Docker and k8s, Go is the platform language so to speak, and although there are extension points for other languages, one has less integration headaches when using Go as well.
It might not be for you, you may rely heavily on Generics in your daily work flow.
If I need generics in my work, I reach for Rust or C++. But when I want to write an easily maintainable microservice that's not trying to reinvent the wheel or need some clever datastructure to handle the work, I reach for Go, since that is what it's good at (at the moment).
The one thing that put me off the most about using C for everything is lack of a common list/vector/map/set standard library for all types. Instead I reinvent the wheel in each project. Go cheats in this regard with compiler magic and that just pisses me off. Atleast you can in theory do printf in iso C.
Edit: And, if Go doesn’t learn from Perl and Python’s mistakes it is going to suffer greatly.
They were also estimating that it will take this long.
IMO they should give shorter time to upgrade, because everyone was waiting to absolute last minute to migrate.
This is less to do with the language and more about the standard library, but it has tons of cross-platform quirks that I feel aren't handled well. For example, Rust's standard library makes cross-platform work less footgun-filled, IMO.
I think that they are just afraid of the income to stop coming in... so they keep working.
"Java, JavaScript (ECMAScript), Typescript, C#, C++, Hack (PHP), and more [...] actively borrow features from one another. They are converging into a single huge language." [0]
[0] https://www.dotconferences.com/2015/11/rob-pike-simplicity-i...
"The key point here is our programmers are Googlers, they're not researchers. They're typically fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They're not capable of understanding a brilliant language but we want to use them to be able to build good software. So, the language that we give them has to be easy for them to understand and easy to adopt."
https://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Fr... at 20:33
Go just makes you productive by removing lots of things to think about. I'm not saying that generics should or shouldn't be part of v1, I'm just saying that go lacking features to make juniors more productive is a feature
I agree with this.
However, the key is to stop once you've implemented the right set of features. Minimalism is about implementing the minimum necessary and no less. I firmly believe that generics are in the right set of features for a statically-typed programming language.
The problem is that Go has already implemented some features which clearly aren't in the right set of features--such as `go generate`--which already allow you to implement a crappy version of generics. So now you're starting to move toward the problem that C++ and (to a lesser extent) JavaScript have, which is that there are 5 different ways to do the same thing, which don't necessarily interoperate well with each other. If go were being implemented from scratch, it would be better to have generics and not `go generate`, but given the language already has `go generate`, there's certainly some downside to adding generics. It's not a simple choice.
To give a proper example, Borland C++ 1.0 for MS-DOS had BIDS, so their own collections library with safe strings and vectors, as it happened with all major C++ vendors back in the day.
Well BIDS 1.0 used pre-processor tricks to generate the desired code, basically you would define the desired types and then include the data structure you cared about, and do this multiple times.
Eventually templates came into the picture and BIDS 2.0 shipped with a template version, based on the ongoing discussions at ISO.
We are talking about 1990 here.
As for the 5 different ways, that is the sin of the languages that start small as a counter movement without understanding that the others are complex not because it is fun to make them complex, rather because languages are products like anything else in software, and either they adapt to their customer base or they fade away.
> As for the 5 different ways, that is the sin of the languages that start small as a counter movement without understanding that the others are complex not because it is fun to make them complex, rather because languages are products like anything else in software, and either they adapt to their customer base or they fade away.
Well, that's somewhat true, but there are two ways to adapt while avoiding the problem of having 5 slightly different and incompatible ways to do the same thing:
1. Pick a good set of language features up front and stick to them, devoting further development efforts to a strong standard library rather than language features. Example: Erlang.
2. Break reverse compatibility and remove things. Example: Python.
If Go really wanted to be open, then Go designers should just have created a virtual machine and let everybody code their own language on top.
Go right now is just basically C with garbage collection. Only C developers love that, and Go designers are well aware that it is an hindrace to adoption in enterprise. The pressure to change seldom comes from the community at large, but Google itself and big corps using Go.
Agreed.
> And it has absolutely nothing to do with genericity, your argument is a fallacy.
In arguments against adding generics, it's been cited numerous times that you can achieve similar code reuse via macros. It's been a while since I looked at the awfulness of `go generate` so I'm not going to attempt to demonstrate the equivalency with that syntax, but here's how you'd achieve something similar to genericity with macros in C:
Instead of:
T swap<T>(T* left, T* right) {
T temp = left;
*left = *right;
*right = temp;
}
...
int a = 1, b = 2;
char c = 'c', d = 'd';
swap<int>(&a, &b);
swap<char>(&c, &d);
You do: #declare_swap_function(T) T swap_ ## T(T* left, T* right) {\
T temp = left;\
*left = *right;\
*right = temp;\
}
...
declare_swap_function(int);
declare_swap_function(char);
...
int a = 1, b = 2;
char c = 'c', d = 'd';
swap_int(&a, &b);
swap_char(&c, &d);
So, macros do have something to do with genericity.Macros are certainly a crappy way to achieve genericity, however, especially since the original reason go didn't include generics was to compile in a single pass, and adding a preprocessor adds another pass.
It's clear you were ignorant here. That's fine--I don't expect you to know everything. But I think it's reasonable to expect that if you don't know what someone is talking about, you approach the conversation with some humility and ask questions before accusing someone of a logical fallacy. Ignorance is fine, arrogance isn't.
The design document for "go generate" listed many motivating use cases, and not one of them was generics. The raison d'être for "go generate" is not to simulate generics. Some people just saw the character sequence "gener..." and made it about generics.
Of course, this was part of an email thread around Common Lisp's popularity in 1999 (https://www.xach.com/naggum/articles/3141310154691952@naggum...) but I think it's more broadly applicable and still relevant two decades later.
Anyway, if you really want a "static" language target, perhaps push hard for official standardization (ANSI, ISO...). Standards encourage a lot of nice things, which admittedly are possible without standards, but less incentivized... For example, I can still write ANSI C as the gods intended, compile other ANSI C written decades ago, using a plethora of compilers across time (including the current year with the latest optimizations) so long as they claim to implement that standard and so long as the code is actually ANSI compliant. Such compilers might implement later standards too, or custom extensions -- but that's ok because it tends to be that I can easily make use of such code and such code can easily make use of mine à la carte! No jihad must be waged on all old code to update it under threat of being relegated to time-capsuled VMs.
But regardless, things will change, even if you have an island of stability from your standard. This isn't necessarily bad, because in order for there to be any improvement, there must be change. "Not every change is an improvement, but every improvement is necessarily a change."
> I think we should start putting weight on stable unchanging software
You would probably like CL then.
I really hope generics, like reflection, are only used when there isn't a simpler option. I honestly would have preferred and had more use for sum types.
I like the square brackets though. They look right for Go and it is more readable.
blessed implementations inside the language, slices, maps and channels are built in generics.
sync.Map is what the standard library version looks like. It loses type safety.
It's incredibly great that, generally speaking, if I'm looking at Go code, the only kind of hashtable there can possibly be is the Go map data structure. The only kind of blocking queue there can possibly be is the Go chan data structure.
You will never see a LinkedTreeDeque or whatever other bizarre concoction someone might come up with. And people don't feel obligated to make every API an iterator of some kind.
Go makes being generics architecture astronautics impossible, and I really love that about it. Perhaps that makes me basic, but I am basic and happy.
They are not "bizarre concoctions".
They are so sufficient you need to learn all these tricks by heart in order to do basic operations on slices:
AFAIK, Golang assigns no special syntactic meaning to angle brackets beyond comparison operators (correct me if I'm wrong though, I don't write much Go), and using a familiar syntax would make it easier to work with coming from other languages.
> AFAIK, Golang assigns no special syntactic meaning to angle brackets beyond comparison operators
Go has also got bit-shift operators << and >>, which wouldn't interact well with angle-bracket notation.
So do Java and C++. This is a solved problem in parsing. The overall point that angle brackets make parsing more complex stands, but bit-shift arguments are irrelevant.
> Angle brackets require unbounded parser look-ahead or type information in certain situations
So they want to avoid angle brackets so they can efficiently parse source code.
- What situations could cause the look-ahead to be unbounded?
- How does the Go parser's implementation differ from those of the languages I'd previously listed which all also have angle brackets for comparison (and bit shifts, as another commenter pointed out) while apparently avoiding unbounded look-ahead?
- What challenges does the Go parser present when trying to adapt it to follow patterns more like those from the other languages' parsers?
- I'm assuming "unbounded" here doesn't mean "it could take unlimited time" but rather "it could incur non-negligible compile-time penalties;" do the benefits of a slightly-quicker compilation (which has nominally no impact on runtime performance) outweigh improved readability?
> - How does the Go parser's implementation differ from those of the languages I'd previously listed which all also have angle brackets for comparison (and bit shifts, as another commenter pointed out) while apparently avoiding unbounded look-ahead?
I think parsing Java or C++ requires unlimited lookahead.
In fact, I think D is the only one using () as well.
template TCopy(T)
{
void copy(out T to, T from)
{
to = from;
}
}
/* … */
int i;
TCopy!(int).copy(i, 3);
The parens can also be omitted in some cases.So.... they'd rather pull the "it's hard to do" or the NIH card, than make it easier for developers switching between languages? Interesting choice. Someone mentioned "condescending" -- that description fits perfectly.
And there I was thinking that COMPILER WRITING should be hard - as hard as possible - in order to make the code which is to be compiled as easy to write as possible.
Go is very easy to switch to from most other languages so I don't think making it harder to switch is a design goal from the team.
When Go came on the scene, I actually really appreciated the fact that they truly explored what a new language could do differently, especially because it was coupled with a strong philosophy.
Now, since 1.0 there have been plenty of decisions made which I dislike. Still, I think the glasses through which you choose look at the Go teams motive aren't fair. Why wouldn't designers of a programming language like Go think it through very carefully, weigh every angle and decide to settle on a lesser used but possible equally valid solution compared to 80% of the languages out there?
They are wrong in this case.
When considering whether to allow `foo<T>();` in Rust, we measured the performance impact that infinite look-ahead / backtracking would have in that case. The result was negligible.
Why? Because the amount you have to look-ahead, before you can say "definitely wrong; let's turn back", in realistic code is bounded to maybe max 30 for some very complex generics. It's however much more likely that no back-tracking occurs at all because the parse will be correct.
When engineering your compiler, you can always make choices about which path is statistically more likely, as back-tracking in a well designed language is usually pathological. The theoretical O(..) complexity is largely irrelevant.
(Source: I was the main maintainer of rustc's parser and refactored large parts of it.)
a, b = w < x, y > (z)
w is lowercase, unambigious. Parsed as list of comparisons. a, b = T < x, y > (z)
Ambigious, so use a, b = T <<< x, y >>> (z)
instead. These cases are very rare. Or demand parens for such ambigious lists of comparisons. Might be too late already.Of just demand the type keyword there also:
a, b = w < type x, y > (z) gen T type pair struct { a, b T } // contrast with type pair(type T) ...
gen T,U type W struct { a T; b U } // contrast with type W(type T, U) ...
gen T func Print(s []T) {...} // print a slice of T
or using `forall` forall T, type pair struct { a, b T }
V readable IMOI wonder how this is solved in Java, and C++, and C#, and...
They even say that it is possible, but it makes producing useful error messages harder and makes the parser more complicated. they are not saying it is not possible, they are just saying it's not preferred to do.
a, b := w<type x,y>(z)
It is definitely better for tooling not to need either, both for human readers and mechanical tools
The example in the mail shows that using angle brackets with Go would require full type information, making simple tools like gofmt impossible.
So now we're making language design decisions based on the limitations of the bonus linter?
My opinion of Golang drops more and more with every new detail I learn about it...
If that's there, it's a generic, else it's an identifier, and somewhere up the parsing chain will take that up as LessThan.
https://blog.dyvil.org/syntax/2016/04/19/angle-bracket-gener...
This operator is affectionately called the "turbofish" and can often be avoided because of very good type inference.
https://github.com/rust-lang/rust/blob/master/src/test/ui/ba...
The key to parsing that is line 35. Is the line a tuple containing two booleans, the first the result of a less than, the second the result of a greater than, or is the line a templated function call, with two template arguments, "woe" and "is"?
(It is the former in Rust, and the latter is the apparently magical third option of
oh::<woe, is>(me)
though of course "woe" and "is" would need to be types, not variables, in that case.)The formatting tool could even normalize that to some prettier unicode.
As for the existing implementation of generic map[K]V, generic []T, chan(T), etc., it's a best-of-both-worlds mix - a kind of erasure (there is only one map implementation in a Go binary) but with a static vtable for accessors without Java's need for boxing - all possible owing to the clever coupling between the runtime and the compiler.
See https://dave.cheney.net/2018/05/29/how-the-go-runtime-implem...
a[x](z)
Is that a read of array a with index x followed by a function invocation with the parameter z.
Where it could also be a type conversion of z into generic type a of x.
But that wasn't my point. It was that we get a ton of BS cosmetic/fun items on the Unicode standards, and we can't get a few simple glyph additions on our hardware keyboards that would seriously help programmers for decades to come...
Beneath that simple surface for beginners lies a multi-paradigm language, with overloading, metaclasses, dynamic code generation, multiple inheritance, breaking changes across minor versions in 30 years of history, a standard library that can be used as doorstep when printed, several implementations not 100% semantic compatible with CPython,.....
But yeah to me Go is pointless and you should better be with C# or Kotlin
How about just code gen your generic implementations then check them in. That way I can see what's going on without having to guess. The whole thing is about saving time typing and DRY right?
With a simple T you do not know anything about the type and you cannot do anything else with it directly except using the root type methods of your type system (e.g get hashcode, toString, etc)
Most generics to be useful needs either: 1) To be type tested (e.g through reflection). This allow you to manipulate it in a fine grained manner and you can know exactly what it's type is. But generally we want 2) to abstract over many types in the same way because those type would have a same invariant, a same behavior. Some language allows you to represent this through union types instead but there's nothing wrong to say that T extend an interface/concrete class that specify what will be accessed from T inside the function. There is no cognitive overhead, no ambiguity. What would have been many types become simpler, factorised under the same contract, the same interface.
If you implement one of those then you'll have another unforeseen problem on your hands, playing wack-a-mole until you have C++. This is a claim, could you explain it? I see no reason to think that way.
C++ "generics" are cancer, we can agree on that.
How about just code gen your generic implementations then check them in. I'm not sure to understand. Would that be like C++ template? What's the difference?
You would like the N redundant implementations of a generic function to be visible? Why desire this clutter? And the alternative, manually maintaining redundant code is error prone and a maintenance burden. Also the fact that there is an invariant, a meaningful intersection of behavior between those types become hidden instead of being explicit through an interface/type test.
what's going on without having to guess. there is zero guess involved as explained above, it's all type safe and your IDE will autocomplete only the shared behavior.