Hacker Newsnew | past | comments | ask | show | jobs | submit | adrianmsmith's commentslogin

One thing I think generics in Go is missing is the <?> concept in Java.

If you're taking a List[T] and all you want to do is to call list.size() then you don't care what type of list it is. In Java you can write a function which takes a List<?> but in Go you have to write List[T] so then the question becomes what is T? You have to make the function (or type you're a method on) generic. If you make the type generic then every user of your type also needs to specify T, etc.

I don't think it would be impossible to add that to Go. Allow List[?], which matches a List with any type parameter. Calling functions which don't involve the type parameter like list.size() would be fine, calling a method returning the type parameter like list.get(n) would return "any", and methods taking the type parameter like list.set(n, obj) would probably not be callable.


Go Generics work differently than those in Java. They are specialized, meaning that they are not generic at runtime anymore. Instead, the compiler creates a different implementation for each type.

At runtime, there are only List[int], List[string], etc. List[T] is not a thing anymore.


The one thing I hated about Java's generics was type erasure. It worked for the JVM but it had such stupid limits, like not being able to switch on a type, like go. (interfaces are types, this is exploitable)


You need this in Java because interfaces are explicitly implemented. You don't need this in Go because interfaces are structurally implemented. The way you spell "anything that has a method named Size which returns int" is interface{Size() int}.


> What people want generic methods for is to do deeply nested call chains

I don't see that as the only use of generic methods.

The example in the article is a "Map" method that transforms e.g. a List[A] to a List[B], by taking a function that takes an A and returns a B. To be able to transform a list like that is a useful operation.

It was possible to do the same with a global function like MapList but the syntax is nicer if you use methods. You don't need the type in the name (function MapList vs method Map) and it is an operation on the List after all so list.Map(..) is nicer than MapList(list, ..).


No


One reason that Go doesn't have sum/union types, from https://groups.google.com/g/golang-nuts/c/0bcyZaL3T8E/m/eL4r..., is that it is not apparent how this would mesh with Go's "meaningful zero value" stance.


People advocate for Go's error handling because it forces you to deal with errors.

But in the cases I do want to catch a specific error, the signature only tells me that a function returns an error, not which type. So I do feel that returning (int, error) is strictly worse than Java's checked exceptions if you care about errors.


This is elegantly solved with sum types. (And arguably needs sub typing.)

If instead of just returning (int, error) the function would return (int, parseError | outOfBoundsError) you would know that the parser function can fail on reading a number at all and on the number being to big/small to fit the type and handle then accordingly.

Saliently, Java in a sense has supported sum types in the throws declaration and the subsequent catch statements forever. Unfortunately it has not landed in other places where you can use types so you cannot use it for returning errors. Scala 3 supports this but has tiny adoption it seems.


That's helped by errors.Unwrap() and errors.Is(), though you do need to build and structure your errors appropriately.


It's helped, but that's runtime behaviour. The compiler can't help you with questions like "you didn't handle certain errors" or "the error you're trying to check can never occur".

Nor does that help with documentation, I'm guessing if I read a file then it might raise the error that the file does not exist. But what exactly is the technical type of that error? You have to search through the function's implementation, and functions that function calls, etc., to find out.

And it doesn't help with refactoring. If you create new.FileNotFoundError and change your function to return it, existing code which checks for old.FileNotFoundError will start to silently fail.


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.


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.


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.


In ocaml (and I assume SML) it helps that the generic types have a `'` before them, so

    val map : ('a Box) -> ('a -> 'b) -> 'b Box


We all know letters are expensive ^^


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.


I'm not necessarily disagreeing, but I'm following the single-letter convention because "TIn" or "InputType" looks too much like an exported symbol. Whenever I tried to write type arguments like that, this threw me off, so I reverted to single letters.


Completely agree and I personally name generic type parameters as I would name types and parameters. It helps a lot.


Swift generics tend to idiomatically use longer names, like Element or View or Content.


I’ve always done that in my typescript code bases too, and I’ve never regretted it


Lambdas usually have short variable names because the scope is small, typically half a line. And that is fine, even optimal.


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


In C# this is the convention.


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...


I believe Haskell did that for decades before C++.


Haskell was created in 1990, five years after C++.


Haskell had generics from the beginning. Whereas C++ only added templates to its specification in 1998.


Miranda had it since its release in 1985.


I was using the STL in 1994 with Zortech C++


The article gives examples of situations where projects have failed, and states a solution.

> The [solution] is to organize the work into the smallest possible learnable chunks and continuously alternate between doing and learning.

It would be more convincing if the article gave examples of where that solution had been tried and succeeded. I mean this must have been tried somewhere, surely.


I feel this article is saying people from UK/US/etc. want to maximize upside, and people from DACH (Germany etc.) want to minimize downside.

I was a bit shocked when I talked to an Austrian colleague once and they told me they wanted to get into investing, but losing any money at any time was completely unacceptable. They had looked at investing in S&P 500 ETFs etc., but felt they must have misunderstood something, as they didn't understand why anyone would invest in anything that might go down, even temporarily.

So the thesis of the article definitely feels plausible to me.


If you invested in the S&P 500 in 1968, you'd be waiting until 1992 before you saw any return on that investment after accounting for inflation, and the inflation adjusted S&P 500 was on a net-losing streak for the whole period from 1968 to 1982 before it started going up again.

People believe the line will always go up, and maybe it will, but it's still at least possible for it to be on a quite painfully downward trend for over 12 years at a time.

I'd argue it's also not at all irrational to worry that we may be on the precipice of a similar situation right now, or perhaps even on the precipice of the situation at the end of the 1920s, where it would have taken more than 35 years for the S&P 500 to recover from its previous highs.

Your colleague is probably more risk-adverse than is rational (and I would say more risk-averse than most Austrians or Germans), but I would also argue that a lot of people blindly throwing all their retirement money at the S&P 500 might not realize just how much risk they are exposing themselves to.

https://www.macrotrends.net/2324/sp-500-historical-chart-dat...


Very interesting trend is S&P 500 to Gold Ratio.

https://www.macrotrends.net/1437/sp500-to-gold-ratio-chart


Real estate, gold, crypto, in that order. That's where people from DACH invest, also valid for rest of the Europe. Mediterranean people additionally invest in lottery tickets. I wouldn't exaggerate saying people are keeping their gold bars in their otherwise empty investment apartments.

European banks play very negative role because they aggressively upsell their investment funds and schemes so for many people stock exchange means investment fund with management fee which oftentimes losses yet the growth, if happens, never catches up with the market growth.


I'm glad this one interaction helped you understand an entire people. That's efficient.


And that's why real estate market is so bad in DE/AT. Folks are terrified of investing in stock market, even through ETFs.

So it's either put everything in a Sparkonto, where it gets eaten by inflation or buy housing.


> But if you have side effects and need something to happen exactly once it seems a lot more useful to communicate this, rather than pretending you did the thing.

I think it depends on whether the sender needs to know whether the thing was done during the request, or just needs to know that the thing was done at all. If the API is to make a purchase then maybe all the caller really needs to know is "the purchase has been done", no matter whether it was done this time or a previous time.

And in terms of a caller implementing retry logic, it's easier for the caller to just retry and accept the success response the second time (no matter if it was done the second time, or actually done the first time but the response got lost triggering the retry).


> Because jj's conflict resolution is fundamentally better

I don't know jj well so its merge algorithm may well be better in some aspects but it currently can't merge changes to a file in one branch with that file being renamed in another branch. Git can do that.

https://github.com/jj-vcs/jj/issues/47


> keeping the old one around would be embarrassing

On the other hand this is the company that sells a Mac Pro for $7k and it comes with an M2-based chip...


Apple refuses to remove things without clear replacements, for better or more often worse.

The 6k XDR has been replaced, apparently they've got something coming for the Mac Pro. I don't know why it wasn't the Mac Studio update last year. Maybe we find out at WWDC this year.


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

Search: