HN user

someone_19

16 karma
Posts0
Comments18
View on HN
No posts found.

No, you’re clearly wrong; golang was always going to add support for generic functions.

Let's get this straight. I'll give you a long quote from Rob Pike's article where he describes the history of the go language:

""" One thing that is conspicuously absent is of course a type hierarchy. Allow me to be rude about that for a minute.

Early in the rollout of Go I was told by someone that he could not imagine working in a language without generic types. As I have reported elsewhere, I found that an odd remark.

To be fair he was probably saying in his own way that he really liked what the STL does for him in C++. For the purpose of argument, though, let's take his claim at face value.

What it says is that he finds writing containers like lists of ints and maps of strings an unbearable burden. I find that an odd claim. I spend very little of my programming time struggling with those issues, even in languages without generic types.

But more important, what it says is that types are the way to lift that burden. Types. Not polymorphic functions or language primitives or helpers of other kinds, but types.

That's the detail that sticks with me.

Programmers who come to Go from C++ and Java miss the idea of programming with types, particularly inheritance and subclassing and all that. Perhaps I'm a philistine about types but I've never found that model particularly expressive.

My late friend Alain Fournier once told me that he considered the lowest form of academic work to be taxonomy. And you know what? Type hierarchies are just taxonomy. You need to decide what piece goes in what box, every type's parent, whether A inherits from B or B from A. Is a sortable array an array that sorts or a sorter represented by an array? If you believe that types address all design issues you must make that decision.

I believe that's a preposterous way to think about programming. What matters isn't the ancestor relations between things but what they can do for you.

That, of course, is where interfaces come into Go. But they're part of a bigger picture, the true Go philosophy. """

Rob Pike, 2012

I can draw a few conclusions from this: firstly, he didn't want to add generics at all because he didn't think they were useful, and secondly, he doesn't understand programming very well and doesn't know what generics are and confuses them with inheritance.

...and Java didn't even have basic enums or sum types from the beginning. But it had null.

They added enums, they added sealed classes. They're trying to get rid of null (apparently it's really hard). The problem is that in 2012, when go 1.0 was released, this should have been obvious to everyone.

Here's a famous discussion from 2009, three years before the 1.0 release (tldr: facepalm)

https://groups.google.com/g/golang-nuts/c/rvGTZSFU8sY

I agree that they were clearly not in a hurry. I disagree that they are doing everything right. I am interested to see how they will fix the 'million dollars mistake'.

Use Your Type System 12 months ago

Unhappy way is a part of contract. So yes, that is what I want. If a function couldn't fail before but can after the update - I want to know about it.

In fact, at each layer, if you want to propagate an error, you have to convert it to one specific to that layer.

Use Your Type System 12 months ago

You can do this quite easily in Rust. But you have to overload operators to make your type make sense. That's also possible, you just need to define what type you get after dividing your type by a regular number and vice versa a regular number by your type. Or what should happen if when adding two of your types the sum is higher than the maximum value. This is quite verbose. Which can be done with generics or macros.

It's essentially impossible to write a Rust program without relying on many of its escape hatches like RefCell and unsafe, that make the borrow checker go away.

This is very contrary to my experience. I don't use cloning or various primitives (except when I really need the shared state).

I can assume that you have this opinion because you see it as a low-level problem while its solution lies at the architectural level.

Use pure functions, group data in structures that own it, get all the necessary data in the controller, process it, and return or store it.

...and using it in function calls would also be inconvenient.

Now I have a clear understanding of what is happening and how.

Nevertheless, using something like this for educational purposes maybe could help. Author of the article In the example with Id literally complains that moving makes moving.

My first thought when I was learning Rust was "Why don't they use a different operator for move?", something like:

let a <= String::from("Hi");

let b <= a;

let j = 0; // Copy

let k = j;

This may not be convenient, but it could be useful for educational purposes.

Second is an absolutely strict programming language, that incorporates not only memory membership Rust style, but every single object must have a well defined type that determines not only the set of values that the object can have, but the operations on that object, which produce other well defined types. Basically, the idea is that if your program compiles, its by definition correct.

That is Rust? This is how his system of types and traits works.

Look at vectors or hash maps. This is a perfect example of the Rust philosophy. Namely, writing complex low-level abstractions that offer a convenient and reliable high-level API.

It uses unsafe, but few people understand what it really is. Rust has clear invariants (for example, that a pointer to T always points to an existing and valid T) that are enforced by the compiler. Using unsafe code is shifting the enforcement of these invariants from the compiler to the programmer. The advantage compared to C is that unsafe code is limited to undefined blocks that are easy to test.

The data structure you describe should be done exactly this way. And it is not a task for the average programmer.