Live data from Hacker News

Toward Go 2

blog.golang.org

551–560 of 670 posts

Re: Toward Go 2

#551
post #535

Earlier quoted context omitted.

I assume that my downvoters do not believe this can be done in a conventional static type system. So I will try to explain further. > The problem munificent was talking about is that for more complex types you cannot write that type checking predicate you want, which would check if a value belongs to the given type and return a variant-free version of the object. The complexity of the type should not matter to a soun…

Dart's choice of an unsound type system doesn't actually matter for those gradual typing problems we were talking about. I think you are getting too caught up in that point. Anyway, going back to the topic, I'll try to explain why your idea doesn't work. > assume a fromVariant function What I was trying to say on my other post is that you can only create such a function for primitive types (numbers, booleans, strings…

> Dart's choice of an unsound type system doesn't actually matter for those gradual typing problems we were talking about. I think you are getting too caught up in that point.

I was trying to show that "gradual typing" should be possible in any reasonable static type system, without resorting to unsoundness. I do concede that there is probably a definition of the term "gradual typing" out there that I am not strictly adhering to.

> Suppose I write down a dynamically typed implementation of the identity function and pass it to some typed code that expects an int->int function. When we pass the function to the typed side we will call fromVariant on it but the best we can do at first is check if the value we have is a function (and not an integer, etc).

If the best we can do is tag it as a function, then fromVariant would unpack it to a function with type Variant -> Variant, which represents all dynamically-typed functions. When we call this function, we indeed would need need to assert the outputs.

> One way to solve this problem is for fromVariant to return a wrapped version of the dynamic function that checks if the returned value is of the expected type

Agreed. Although the danger of this is that you have a bomb waiting to go off inside some unsuspecting piece of typed code. The alternative to to acknowledge that it is a partial function in the type, e.g. the Variant -> Variant function becomes Int -> Maybe Int, or similar. The point is that we are solving these problems using conventional static typing. You haven't yet convinced me that this doesn't work.

> You will either need to do a runtime check when the dynamic code writes to the array (which slows down the dynamic code) or you need to add runtime checks when the static code reads from the array (which makes it slower than it would be in a fully static language).

It sounds like you are concerned with performance and efficiency, that may indeed be an issue, but it's orthogonal to the type system. My own position is that if one wants performance, then don't write untyped code!

> If you are interested I can send you links to a couple of gradual typing papers. As munificent said, there is currently lots of ongoing research about this and we all wish it were as simple as you were suggesting it would be

Thanks for the offer, I am definitely interested. I suspect that the outstanding issues are around usability and efficiency. I stand by my original point that "gradual typing" should be possible in any sufficiently expressive static type system.

Re: Toward Go 2

#552
post #538

Earlier quoted context omitted.

I respectfully disagree. The "right membrane" around any untyped value is a Variant type. A static type system would then stop you making any assumptions without unpacking and asserting its type. If we don't want variants and just want to defer type errors until runtime, then this is possible too (GHC Haskell can do this).

GHC's Dynamic type can only contain monomorphic values, it can't handle polymorphic stuff. GHC also considers Dynamic->Dynamic and Int->Int to be incompatible types, which is not quite what one would want in a gradualy typed setting. Haskell also sidesteps the difficulties that come with mutability in a gradualyly typed setting.

I did not mention GHC's Dynamic type. I mentioned GHC's deferred-type errors as an alternative technique to "gradual typing". I believe there were plans to implement a polymorphic version of Dynamic, but it obviously wasn't a high priority. Note that GHC does not require any special type-system extensions to support Dynamic.

Re: Toward Go 2

#553
post #222

Earlier quoted context omitted.

The dynamic type was added to C# to facilitate interoperability (ex. DLR), not so much to encourage lazy devs to get their bugs at runtime rather than compile time.

I still do not understand why this cannot be done via a Variant type. Also it doesn't explain why Dart 2 has a similar feature.

> I still do not understand why this cannot be done via a Variant type.

Makes little difference, either way you need a magical type since it has to allow any method call at compile time, and then requires enough RTTI that it can check for and dispatch method calls at runtime. Whether you call it Variant or dynamic has no relevance.

Re: Toward Go 2

#554
post #399
post #326

Earlier quoted context omitted.

it's a bummer that the windows story for ocaml is so sketchy. i'd like to use it for work (various utilities and whatnot) but the ecosystem seems to make a lot of assumptions about the system it runs on. (for me there's still haskell and rust at least.)

How about F#?

All the advantages of ocaml, cross platform, great tooling

Re: Toward Go 2

#555
post #453
post #449

Earlier quoted context omitted.

What are the very real downsides that generics have?

Binary bloat and general difficulties with how one handles variance in light of people's expectations.

> Binary bloat

That sure is a concern when just importing fmt increases your binary size from 900k to 1.6M…

Re: Toward Go 2

#556

Earlier quoted context omitted.

The request for use cases in Go seems a bit like begging the question to me. Since Go doesn't have generics, anything designed in Go will necessarily take this into account and design around this lack. So it's relatively easy to show that Go doesn't have a compelling use case for generics, since the designs implemented in Go wouldn't (usually) benefit from generics! Rust has generics and traits/typeclasses, and the r…

This suggests that both generics and inheritance are unnecessary.

Assemblies over the ages denote that so are loops, functions[0] and named variables, you can do everything using addresses, offsets and jumps.

They sure are useful to readability and maintainability.

[0] which can obviously be used to replace looping constructs anyway

Re: Toward Go 2

#557
post #291

Earlier quoted context omitted.

I'm not even a Go developer, I just played with it a bit a couple of years ago and used it for a small one-off internal API thing, and I can think of a dozen real-world use cases for generics off the top of my head. * type-safe containers (linked lists, trees, etc.) * higher order functions (map, reduce, filter, etc.) * database adapters (i.e. something like `sql.NullColumn ` instead of half a dozen variations on `sq…

I would also love Result in as a return type in place of (err, myThing)

Yeah, using a tuple for what clearly should be a disjoint union is infuriating. I really don't buy the gopher argument that 'it is hard to understand'.

Re: Toward Go 2

#558
post #416

Earlier quoted context omitted.

> Clearly he meant to ask for examples from the real world that lack generics, but shows how adding them would improve the system. I don't think many such examples will emerge. First, you have the empty interface escape hatch. It's cumbersome, but it works. The real reason why the repeated use of this escape hatch (instead of proper generics), is lack of compile time type safety, which is replaced by dynamic checks.…

Ok, thanks for the clarification. I wonder if there are situations in big teams in which one team that uses generics can take a look at a large Go codebase within the same company and see what they think? They must have received such feedback at Google, surely?

Most probably. But they might ignore it anyway.

There's at least one high profile example: the standard library itself. It must have been obvious by the time they designed the standard library, before the language was out. They had to have feedback then, just look at the trail of rage against the absence of generics.

They ignored it then —I have no idea why. I'm not sure they'll listen now.

Re: Toward Go 2

#559

Earlier quoted context omitted.

I would start using Go in my projects if it introduces generics. It's a show stopper for me.

The question is _why_ do you need generics, for what use case(s), etc? Saying “I need generics otherwise I won’t use Go” is exactly the type of feedback they don’t want. It seems like you’d have valuable feedback given that it’s a “showstopper” for you.

Try implementing LINQ in Go, while using no runtime type assertions at all and maintaining compile-time type safety (ie: no interface{}).

Then you'll wish you had generics. :)

Re: Toward Go 2

#560
post #426

Earlier quoted context omitted.

It's generally the opinion of the Go community that map, reduce and filter are bad ideas due to how easily they are abused. A for loop gets the job done easily enough. If you've ever worked with data scientists working with Python, you'll quite often see them all chained together, probably with some other list comprehensions thrown in until it becomes one incomprehensible line.

If that's the case, then the Go community is wrong. For loops do not get the job done easily enough. I've lost count of the number of times I've had to do contortions in order to count backwards inclusive down to zero with an unsigned int. With a proper iterator API, it's trivial. Furthermore, for loops are a pain to optimize. They encourage use of indices everywhere, which results in heroic efforts needed to elimina…

> For loops do not get the job done easily enough.

There was a nice paper at this years POPL which (in my opinion) allows you to substantiate this claim.

The paper is "Stream Fusion to Completeness", by Oleg Kiselyov, Aggelos Biboudis, Nick Palladinos, and Yannis Smaragdakis. The actual question in the paper is how to compile away stream operations to imperative programs using for/while loops and temporary variables. On the other hand, if we look at the output of the compiler we can see how complex it is to express natural stream programs using only for/while loops.

For instance, even very simple combinations of map/fold/filter create while loops and make it difficult to detect the loop trip count afterwards (in fact, you need an analysis just to detect that the loop terminates). If you combine several such streams with zip, the resulting code makes a nice entry for obfuscated code contests. Finally, if you use flatMap the resulting control flow doesn't fit into a for/while loop at all...

So for/while loops are not simpler than stream processing primitives and unless you explicitly introduce temporaries (i.e., inline the definition of map/fold/etc.) you quickly end up with very complicated control flow.

Post reply on HN