Live data from Hacker News

Things about programming I learned with Go

mjk.space

91–100 of 157 posts

Re: Things about programming I learned with Go

#91
post #69

Earlier quoted context omitted.

>A sum type `T = A | B` means that a value of type `T` can be either of type `A` or of type `B`. Such a type is used to express polymorphism. Taking this example (in English / pseudocode): Define a class Animal. Define Dog as a subclass of Animal. Define Cat as a subclass of Animal. Case 1) Now if we have a variable a1 that can, at runtime, contain (or refer to) either a Dog or an Animal instance. Case 2) And if we h…

Both. Assuming that you can actually exclude instances of class Cat in case 1 and of Animal in case 2, that is. In case 1, the actual type of a1 would be Animal | Dog. In case 2, the actual type of a2 would be Dog | Cat. (Either a1 or a2 might be declared with a different type, this is about the values that they can actually hold, according to your stated premises.)

>Both. Assuming that you can actually exclude instances of class Cat in case 1 and of Animal in case 2, that is.

Good point. I was actually thinking in terms of Python OOP, and in that, you cannot exclude those instances (at least not without some extra code).

Re: Things about programming I learned with Go

#92
post #88

Earlier quoted context omitted.

>final case object Red extends Color On a side note, that syntax seems a little counter-intuitive - the extends word seems to indicate that Red is a subclass of Color, but from what you said seems more like Red and Green are values for Color. So it seems like an enum would be more appropriate here (for this use of Red, Green and Color)?

A Scala “object” declaration declares a singleton; it's an object, but you can also define object-specific class features. If the instances need behavior (which in practice they often do), this is useful. Presumably, in the example, they would in a substantive program, but the behavior is irrelevant to the illustration and thus omitted.

Interesting, thanks.

Re: Things about programming I learned with Go

#93
post #50
post #18

Earlier quoted context omitted.

'A more meaningful statement would be: "use inheritance to express sum types, use composition to express product types."' I'm not sure how well that works as a meaningful statement, because it assumes that the reader has a solid grasp of what a sum type and a product type are. If not (and I make the perhaps dubious assumption based on my own experience and knowledge that most programmers, especially most people using…

That's ... sad. Sum types and product types are simultaneously easier to understand and are more useful to know about than inheritance. Sum types are simply types whose values can be one of several choices - surely that's something a child can reasonably understand! Product types might be a little harder to grok - they're essentially structs - but surely no harder to understand than inheritance and the whole IS_A/HAS…

No, sum types and product types relate to values, inheritance and composition relate to objects, which include values AND behavior. Inheritance is therefore abused to share behavior. This distinction is important, and relates to some common OOP patterns of popular languages.

In that model, composition of behaviour over inheritance is definitly important to understand, as overriding behaviour gets tricky quickly, and functionality is spread accross many class in the inheritance chain, it becomes difficult to follow and see the full picture.

Re: Things about programming I learned with Go

#94
post #93
post #50

Earlier quoted context omitted.

That's ... sad. Sum types and product types are simultaneously easier to understand and are more useful to know about than inheritance. Sum types are simply types whose values can be one of several choices - surely that's something a child can reasonably understand! Product types might be a little harder to grok - they're essentially structs - but surely no harder to understand than inheritance and the whole IS_A/HAS…

No, sum types and product types relate to values, inheritance and composition relate to objects, which include values AND behavior. Inheritance is therefore abused to share behavior. This distinction is important, and relates to some common OOP patterns of popular languages. In that model, composition of behaviour over inheritance is definitly important to understand, as overriding behaviour gets tricky quickly, and…

> No, sum types and product types relate to values, inheritance and composition relate to objects, which include values AND behavior. Inheritance is therefore abused to share behavior

I remember back in high school or early college I was having a conversation with a programmer about when the right time to use inheritance is, and he stated that "inheritance should be used for polymorphism, not just to share code", which to this day I think it's a fairly good heuristic for determining whether or not inheritance is the right tool for a given problem.

Re: Things about programming I learned with Go

#95
post #20

I'm no Go expert, so the following may just come from having not used it enough. The two things that shocked me out of continuing with Go were exception handling and package management. Exception handling is basically not implemented. Instead the Go developers dediced to add half a step from return codes towards exceptions and work with that. And now the community seems to have decided to just reraise everything that…

Package management is currently been worked and the tool[1] is stable now, at least the user facing parts. Here's where things stand as of a few days ago[2] There has been efforts to use dep in kubernetes[3][4]

1. https://github.com/golang/dep

2. https://sdboyer.io/dep-status/2017-08-17/

3. https://github.com/golang/dep/issues/110

4.https://github.com/golang/dep/issues?q=is%3Aissue+kubernetes...

Re: Things about programming I learned with Go

#96

Earlier quoted context omitted.

Inheritance is not a way to express sum types, it's a form of subtyping. A sum type is like a discriminated union, it can only be one thing at a time. Subtyping allows a value to have multiple (related) types simultaneously, which is much more expressive. I suppose you can use one level of single inheritance to emulate a sum type, but you could just as well emulate it with a discriminated union in Go, e.g. a struct w…

I'm finding that wrapping an interface in a struct can be a good technique. However, the interface{} contains a type identifier, so adding another one seems like wasted space. Usually you can compute it using a type switch.

Yeah, that's a perfectly valid solution as well. Depending on the application it may be faster to do the assertion on your type identifier rather than introspecting the type though. And having a list of type options more directly maps to a true sum type. I probably wouldn't actually do it in real Go code if I could avoid it though

Re: Things about programming I learned with Go

#97

> It’s better to compose than inherit I know that this is just a restatement of the "composition, not inheritance" mantra in Go, but it still makes about as much sense as "product types, not sum types". A more meaningful statement would be: "use inheritance to express sum types, use composition to express product types." There's no "better" relation between the two concepts, each has its own distinct purpose. Yes, in…

"but that's a misunderstanding of what inheritance is used for"

I'm not sure what you imply. Most OOP languages where people tell you not to use inheritance, but composition instead, so java, c++, c#, etc. In those languages inheritance can be used to create forms of product types, but also to share and override behaviour hierarchically. They can also create sum types, and all possibility of hybrids, like weird mix of sum and product types, partially closed, etc.

By allowing inheritance to do all this, I say it doesn't matter what the designer of these languages intended inheritance to be used for, the truth is that it allows for much more, and so best practices have been put in place to help programmers not use the construct in troublesome ways. One of those is to use composition instead.

Can you simulate closed sum types with inheritance, yes, but they are not the same thing clearly, since closed sum types can not emulate all usage of inheritance (the kind of java).

Maybe you're right, a closed sum type pattern could be created and evangelized, having an abtract class with no fields and a set of methods, then having a one level inheritance hierarchy where each subclass has its own disjoint set of fields, and overrides all methods to work on its fields. But I already feel like in practice this sounds like a nightmare. Too much good intentions are needed to maintain this, its too easy to create a degenerate case of it.

Re: Things about programming I learned with Go

#98
post #83
post #79

Earlier quoted context omitted.

I'm not sure if you can really express it in OO. Sum types are used to represent a closed set of variants. Inheritance like that isn't closed. In languages that have both OO and ML/Haskell-style type systems like Scala, the fact that the set is closed is denoted by the keyword 'sealed'. example sealed trait Color final case object Red extends Color final case object Green extends Color Color can only be Red OR Green.…

>Color can only be Red OR Green. In your example you can have an Animal, a Dog, a Cat, and other things can inherit Animal and create more variants. True. I used traditional OO style inheritance in my example, and my question was about understanding the relationship between it and sum types, based on rbehrends' comment that I was replying to. Interesting, did not know this. So you are saying that sum types are sort o…

> So you are saying that sum types are sort of like inheritance with some limits

Traditionally sum types don't have inheritance, you have the sum type is a type and the variants (or constructors) are values of that type, but yes you could also model it as a "closed inheritance" hierarchy, in fact some languages do exactly that: Scala with sealed traits and case classes (the trait is the sum type, each class is a variant) and Kotlin with sealed classes.

The boundaries can also get fuzzy the other way around, OCaml has polymorphic variants and extensible variants which blur the line. Polymorphic variants are structural types where multiple sum types share the same value (polymorphic variant types are venn diagrams essentially), not entirely unlike integral types, and extensible variants (as their name denotes) can get cases added to them by users of the base package/type.

> Sort of like an enum

Sum types can be seen as an extension of enums yes, Rust and Swift call them that, in both languages they're enums where each "value" (variant) can carry different data sets (unlike e.g. Java enums where variants are instances of the enum class). Here's a "degenerate" C-style enum with Rust:

    enum Color { Blue, Red, Green }
and here's one with associated data:

    enum Color {
        RGB(u8, u8, u8),
        HSL(Hue, Saturation, Lightness),
        CMYK(u8, u8, u8, u8),
    }

Re: Things about programming I learned with Go

#99

Earlier quoted context omitted.

There's a lot of languages that can make that claim, and lots of developers that would pick up a new C-like language in a week or so. The challenge is that companies that picked Go or $uncommon_language need to provide the space and training opportunity. Go may be easy to learn, but mastering it is a thing on its own, just like the other languages.

Go's spec is much smaller than most mainstream languages. Seriously, it's a weekend read to understand the entire language specification (and it's actually readable)

The go board game has an extraordinarily simple rule set. On the other hand, it is an exceedingly difficult game to gain proficiency in.

A simple spec does not equate to a simple language. I would argue the opposite: a simple spec often means a large amount of hard work is punted on and left to the end-user.

Re: Things about programming I learned with Go

#100

Earlier quoted context omitted.

Mastering a language is not the same as reading the entire spec, or even internalizing that spec. Scheme or Forth or Io are all probably smaller than Go. Perhaps even smalltalk is (the Smalltalk 80 spec is larger, but contains some of the library, tutorials, examples, and the entire spec for compiler and the VM). If you really want an extreme example language with the tiniest spec, you can always take Brainfuck. The…

My comment mentioned mainstream languages. To my knowledge, Brainfuck is not a mainstream language used at any small, medium, or large corporation. The point about the spec was the language is small enough to master. Scheme (Lisps in general) is different because it is homoionic. Forth is not mainstream, and neither is it's paradigm. And well, I never heard of Io so I will check it out, looks neat.

And your point was refuted. Brainfuck not being mainstream is irrelevant; either a short language spec correlates with speed and easiness of mastery or it doesn't. And the counter-evidence shows that it doesn't.

You can't just casually ignore inconvenient exceptions to your beliefs. I mean, you can, but it's not something that reflects positively.

Post reply on HN