baalimago
8 hours ago
This: "(b Box[T]) Map[U any](f func(T) U) Box[U]" is the type of cognitive weight I was happy that Go avoided.
fauigerzigerk
6 hours ago
It's hard to avoid, because (naming aside) the cognitive load is caused by higher order functions, which are hard avoid without causing massive code duplication.
I understand the desire to keep things concrete and avoid high level abstractions, but it's a decision not to automate stuff that can easily be automated. It runs counter to the basic instincts and purpose of our field/industry. That's why it never sticks.
hnlmorg
4 hours ago
Honestly, I’ve written some applications that, on paper, should be the perfect candidate for generics. And yet I can still count on one hand the number of times generics have saved me from massive code duplication.
Most of the time generics might be useful, I’ve ended up needing reflection too anyway. And at that point, I’m really no better off for generics.
fauigerzigerk
4 hours ago
I understand that this is true for a lot of application code. It's not true for library authors though, and every language needs libraries.
hnlmorg
3 hours ago
I’ve written a lot of libraries too.
The problem is generics only solve a very small part of the equation: compile time checks for composite types. But to use composite types in anything non-trivial in Go, you then need reflection. Which is slow. And if you then need reflection, you’re already passing interface types anyway plus you’re back to having to handle type-handling errors in the runtime.
So if you’re writing a library that’s expected to have any kind of performance, you’re back to code duplication and having a DoSomethingType() function signatures again.
Or you stick with reflection and take that performance hit PLUS the risk of compile time constraints being runtime errors; which is the a lose-lose scenario. And let’s also not forget that reflection can be just as verbose as code duplication, and harder to get right too.
Don’t get me wrong, I’m glad we have generics. But people on HN massively overstate the value of them in a AOT non-dynamic, strictly typed language like Go.
I guess you could argue that Go has other shortcomings that directly result in generics having limited value. But then you’re basically just arguing that you prefer coding in a different language paradigm, and at that point, you’re much better off using that other paradigm instead of complaining that Go isn’t JavaScript or Haskell.
Pay08
6 hours ago
Lisp manages it. Even if you do use type annotations.
fauigerzigerk
6 hours ago
No. This cognitive load is conceptual. You can't avoid it by using slightly different syntax.
zerr
44 minutes ago
We often forget that our profession (computer programming) belongs to STEM. Some (like Go 1.0 :)) wish to think it is Arts & Humanities. The sooner we realize that yes, it is OK and actually expected to bear a cognitive weight of "(b Box[T]) Map[U any](f func(T) U) Box[U]" the sooner we get back to reality... :)
red_admiral
22 minutes ago
Just because we can, doesn't mean we have to. I'd prefer to have some more brain-cache free to concentrate on the problem I'm trying to debug rather than doing type resolution in my head.
thebytefairy
24 minutes ago
People should stop using these simplified high level programming languages with low cognitive weight, like Go. I only write assembly. ;)
teh64
4 hours ago
I think naming conventions might help:
(b Box[InType]) Map[OutType any](transformFunction func(InType) OutType) Box[OutType]
Same in Python: def map[U](self, f: Callable[[T], U]) -> Box[U]
vs def map[OutType](self, transform_function: Callable[[InType], OutType]) -> Box[OutType]
and Java: public <OutType> Box<OutType> map(Function<InType, OutType> transformFunction)
vs. public <U> Box<U> map(Function<T, U> f)adrianmsmith
7 hours ago
I never understood the convention of using single letter names for generic parameters. I guess this started in C++ and every language has copied that convention.
I think that code would be a lot easier to read if the types were called IN and OUT or In and Out or TIn and TOut or something like that.
toinebeg
5 hours ago
I often use whole word for type annotation, when I can find meaningfull ones. I just type them in all caps to stay close to the convention.
I guess the single letter thing is laziness for a part. It's not simple to find words that represent the abstract idea behind the generic type without narrowing the possibilities. For array function, the Key Value from the sibling comment work but for more complex use case, it get complicated.
jiehong
7 hours ago
We all know letters are expensive ^^
wwalexander
3 hours ago
Swift generics tend to idiomatically use longer names, like Element or View or Content.
girvo
3 hours ago
I’ve always done that in my typescript code bases too, and I’ve never regretted it
spockz
6 hours ago
Completely agree and I personally name generic type parameters as I would name types and parameters. It helps a lot.
Someone
6 hours ago
For maps, a convention is to use K and V for key, respectively Value.
I think that’s best as you’ll soon learn the “single-character capital letter ⇒ generic parameter” convention
Laurel1234
5 hours ago
In C# this is the convention.
eterm
an hour ago
It's a mix, because some stuff tends to just use `T`, but there's better descriptors elsewhere.
There's IList<T> but Task<TResult>
There's Action<T1, T2, T3, T4, T5, T6> but also Dictionary<TKey, TValue> and Map<TIn, TOut>
This stuff kind of "makes sense" once you're used to it, because it's difficult to say what IList<T> ought to have been called otherwise, IList<TContainee> is a mouthful, and Action<T1,...> simply suffers from the inability to specify an unknown number of generic parameters.
https://learn.microsoft.com/en-us/dotnet/api/system.collecti...
https://learn.microsoft.com/en-us/dotnet/api/system.action-2...
https://learn.microsoft.com/en-us/dotnet/api/system.collecti...
setopt
5 hours ago
I believe Haskell did that for decades before C++.
logicchains
4 hours ago
Haskell was created in 1990, five years after C++.
phplovesong
7 hours ago
Im pretty sure it came from the MLs, where you usually have a/b/c instrad of the T,U etc combo.
I dont find it confusing, as its pretty clear that it only an placeholder.
In generics the name usually does not matter or is REALLY hard to name so that it makes sense.
More specifically in Go where you have interfaces, concrete types and generics.
teh64
4 hours ago
In ocaml (and I assume SML) it helps that the generic types have a `'` before them, so
val map : ('a Box) -> ('a -> 'b) -> 'b BoxasQuirreL
6 hours ago
Fairly sure it would predate even that, and go all the way to lambda calculus, and predicate logic before that, and that's where my knowledge stops and somebody else can tell us where the current conventions around variables in logic and mathematics come from.
red_admiral
24 minutes ago
Indeed, we're now one step away from monads. I know https://go.dev/doc/effective_go hasn't been updated for while, but it also seems to have been forgotten. "Go is an open-source programming language that focuses on simplicity ..." the page begins.
treyd
12 minutes ago
You've already been able to badly implement monads in Go for 10+ years. Why wouldn't you be able to implement them in a way that the compiler can enforce correctness of?
If you don't want it don't use it. It's that simple.
inigyou
17 minutes ago
Apparently the people responsible for the simplicity retired. Since it's Google, some new people want to be promoted for adding features to Go.
dvdkon
6 hours ago
Maybe it's just familiarity, but I think it would look a lot more comprehensible with some punctuation. Just because a syntax is formally unambiguous doesn't mean it looks that way to humans.
func (b: Box[T]).Map[U: any](f: func(T) -> U) -> Box[U]mseepgood
3 hours ago
It's not good Go code anyway. In Go you would use a for loop. Just because Go has generics nowadays doesn't mean you should abandon good taste and write ML/Haskell/Rust/C# in it.
twsted
6 hours ago
I really understand your feeling, I escaped from C++ years ago when I was overwhelmed by meta programming (initially i loved it).
But anyway I find this in Go much more bearable.
HumblyTossed
an hour ago
Right? Sigh. I really dislike this.
There are 37000 programming languages, stop forcing every single one that gets popular to look like this.
kitd
6 hours ago
It looks more reasonable (literally lol) with syntax highlighting though.
scotty79
4 hours ago
> (b Box[T]) Map[U any](f func(T) U) Box[U]
Map method
of b (of type Box[T])
that takes f
(of type function that takes value of type T and returns value of type U (which could be any type))
and returns value of type Box[U]
is defined as follows
return Box[U]{v: f(b.v)}
func[U any] b:Box[T].Map(f:func(T)->U)->Box[U]:
return {v: f(b.v)}
func[U any] Box[T].Map(f:func(T)->U)->Box[U]:
return {v: f(this.v)}
// maybe all of the types could be inferred from usage?
func Box[].Map(f):
return Box[]{v: f(this.v)}
Eh... I think you'd need to avoid generics altogether.inigyou
13 minutes ago
that's literally what Go was supposed to do! If I want a language like C++, I know where to find a language like C++ (it's C++).