Enumeration types in rust can be the usual ones you find in other languages:
enum UserStatus {
Anonymous,
Registered,
Confirmed,
}
But their variants are not limited to names, they can be other things[1]: enum UserStatus {
Anonymous,
Registered{ email: Email, date: Date }, // a struct
Confirmed(date), // a tuple
}
Enum types can also be made generic. For example the Date type could be a parameter in the example above: enum UserStatus<T> {
Anonymous,
Registered{ email: Email, date: T }, // a struct
Confirmed(T), // a tuple
}
Which brings us to the Option type[2] in rust. It is an Enum with a generic type attribute, defined like this: enum Option<T>
{
Some(T), // a tuple with a single item of type T
None,
}
In rust, when a function says it returns an `i32`, it will always return an `i32`. It never returns `i32 or null`.If you want not return an `i32` sometimes, you must specify exactly what else it can be. It is often convenient to return an Option<i32> instead. Then it can return `Some(i32)` or `None`. The difference with the "implicit null" from before is that the compiler will force you to "deconstruct the option safely", in compile time. You will never get a "Null Pointer Exception" in run time because of this.
For me, this is huge, and one of the reasons I like Rust more than Go.
[1]: https://doc.rust-lang.org/rust-by-example/custom_types/enum.... [2]: https://doc.rust-lang.org/std/option/
You can can implement this generically in Go using interface{} types and runtime type checking, but then you have runtime type checking failures.
A java/c++-esque "generics" implementation would be able to type-check at compile time.
Go has the most useful containers built in. Most code I write doesn't need custom containers, even in languages with templates (I write far more C++ and Java than Go) -- so I find that I don't miss them much when I spend time in Gopherspace.
I suppose it's not sorted or concurrent-safe?
`map[T]struct{}` is only a type, it's not an implementation. You still need a handful of methods, that might be named inconsistently in each implementation by different developers. I will be happy when I never have to think about this again
Set storage is not really the concern here, it's the set-theoretic operations which make sets useful (generally speaking, there are cases where all you need is the set being a set e.g. deduplication).
So I wouldn't be surprised that GP found several different implementations of union, intersection, difference, symmetric difference, subset, superset, …
That means for every conceivable input type and output type combination you have to have a new MAP or REDUCE function to handle it.
All Modern languages except golang and elm only require one implementation of MAP that can handle all type combinations.
It's called parametric polymorphism.
I seem to remember an article being written a while ago that found Java's type system, with the addition of generics, was unsound. Maybe that's what you're trying to say.
You can do exactly the same thing in Golang. Just use interface{} everywhere and add few casts where needed. That is Java generics.
That's not true, Java generics are not just syntactic sugar.
> They don't add anything substantial.
They add parametric polymorphism and type safety.
> You can use Object (or another bound type) everywhere you're using generic type.
Only if you go out of your way to do so, and ignore warnings. This has less to do with how generics work in Java and more to do with the fact that Object can be explicitly cast to another type and vice versa.
> You can do exactly the same thing in Golang. Just use interface{} everywhere and add few casts where needed.
No, it's completely different.
One example is to look at how Go handles the Image package vs other languages with generics. https://golang.org/pkg/image/
Traits is a way to solve it. But the problem is that in Go types are "too open". If you wanna constrain it more traits is not an elegant solution.
Generics is better in this case.
BTW: This is how is in Rust. Rust have traits but you fill the rest with generics.
I made a mini-go database command liner that I call from rust (so I get access to drivers that are not yet available in rust). Is much more boilerplate from some stuff that in the rust side is just Value<T>.
And type errors that Go have that rust don't.
I think that Rust & Go sharing some(most?) design principles (about how model types) make easier to see what each side make harder...
The difference is in speed of producing such code, amount of bugs introduced, ability to understand, modify, and evolve the code, etc.
What would you call a language that forces you to write / use a preprocessor to introduce higher-level features?
Low-level. More specifically, low-level for the domain where you're working. C is admittedly low-level because it had to be minimal even for 1970 and close to the metal. Other languages usually enjoy less drastic design constraints.
I let you research when it was released.
Then I ran unit tests, and sometimes a weird error cropped up. Turns out I made an error in an append: instead of concatenating two arrays, I added the second array as the last element of the first. That was a time consuming bummer.
This problem could have been prevented by two approaches: copying every function for every type, or generics.
Go is a nice language, which makes some tasks easy to implement, almost fool proof, but it still lacks in other areas.
Go makes you implement max and min in all your codebases.
In Go, I believe you need to give up type safety to write these implementations, by using Interface{}
Generally it makes more sense to describe an interface that can be satisfied by different types, and writing logic to handle that interface instead. Go may not have traditional generics but the interface pattern is certainly a kind of generic programming that can be used to achieve some powerful results. Because structs can satisfy many interfaces and interfaces can be satisfied with any kind of struct (if you want an in language example check out the io.Writer interface and the many functions that use it) you can end up with highly reusable code despite not having traditional generics.
You can get away without them in many cases, but if you are working on stuff that you want to reuse, generics are the way to go. In combination with Rust’s traits this is especially cool.