Live data from Hacker News

Algebraic Data Types for C99

github.com

101–110 of 233 posts

Re: Algebraic Data Types for C99

#101

One of the crimes of modern imperative programming languages is not having ADTs (except maybe Rust) built-in. It is such a basic mental model of how humans think and solve problems. But instead we got inheritance and enums which are practically very primitive.

>> not having ADTs (except maybe Rust) built-in Most of the common languages today have product types. Java[1], Rust, Haskell, etc. have sum types. I think it gets a bit more escoteric beyond that though - i don't doubt that there's probably some haskell extension for quotient types[2] or some other category theory high-jinx. Most languages have ADTs built in. [1] https://blogs.oracle.com/javamagazine/post/inside-the…

Please don't forget Dart!

https://medium.com/dartlang/dart-3-1-a-retrospective-on-func...

Re: Algebraic Data Types for C99

#102

One of the crimes of modern imperative programming languages is not having ADTs (except maybe Rust) built-in. It is such a basic mental model of how humans think and solve problems. But instead we got inheritance and enums which are practically very primitive.

Isn’t ADT abbreviation for Abstract Data Type? Or does it depend in context nowadays?

You answered your own question: it depends and the context and is confusing imo. Both are very common in compsci

Re: Algebraic Data Types for C99

#103

Earlier quoted context omitted.

You're approaching this from a PL design standpoint where the distinction is important, but from a user perspective it doesn't matter if it's just "syntax sugar" or if it's a super complicated to implement all that matters is whether the feature is available or not.

Typing features affect the way we design APIs. Libraries written in languages with type classes and without them can have completely different designs. If nested pattern matching is not available, this will not affect the APIs, only the function bodies -- because desugaring is local by definition.

That doesn't matter in practice. If two programming languages have the same underlying feature but one has syntactic sugar to make it very easy to use and the other does not (so is quite cumbersome to use) then you'll find that the library ecosystem for the former language will see the feature in widespread use whereas the ecosystem of the latter will tend to shun the feature.

This is one of the social factors of programming language design and it's one of the main reasons successful programming languages work so hard to establish a coherent philosophy and a set of best practices or idioms within the language. For similar reasons, I believe this is why "anything goes" languages such as LISP have struggled to gain widespread adoption: with no philosophy every programmer becomes an island unto themselves.

Re: Algebraic Data Types for C99

#104

Earlier quoted context omitted.

>> not having ADTs (except maybe Rust) built-in Most of the common languages today have product types. Java[1], Rust, Haskell, etc. have sum types. I think it gets a bit more escoteric beyond that though - i don't doubt that there's probably some haskell extension for quotient types[2] or some other category theory high-jinx. Most languages have ADTs built in. [1] https://blogs.oracle.com/javamagazine/post/inside-the…

Java's sealed classes are still somewhat more limited than Rust's or Haskell's sum types, in that each instance of the superclass holds a fixed variant (i.e., subclass), so you can't change the variant without creating a new instance. Clearly, this limitation is necessary for references to stay intact, but I've personally ran into this issue when trying to represent a sum type in an ORM.

I don't really think it's useful to do that though?? Can you give an example?

By the way, I would claim Java's sum types are less limited than Rust because in Rust, variants don't have their own type. The consequence is that you can't have functions that only accept some variant, as far as I know (I remember having this problem once), or add "methods" only to one variant... while in Java, because variants are just normal types, you can do both, and doing that is pretty damn useful.

Re: Algebraic Data Types for C99

#105
post #8
post #7

Earlier quoted context omitted.

Sealed interfaces in java 21 allow pattern matching

Yeah I know, we just don't use Java 21 at work yet. I'm super excited for that update, and it actually looks like we will be transitioning to that by the end of the year, but I haven't had a chance to play with it just yet. I do find it a little annoying that it's taken so long for Java to get a feature that, in my opinion, was so clearly useful; it feels like they were about a decade later on this than they should h…

If you can enable preview features, you can use pattern matching since Java 17 (though the final syntax in Java 21 was slightly changed - still you may want to use preview features, it's mostly fine in Java as they tend to change very little, and when you do upgrade, the compiler will tell you where you need to update your code).

Re: Algebraic Data Types for C99

#106
post #99
post #61

Earlier quoted context omitted.

This argument is the most common fallacy I see in programming language discussions. I might as well give it a name right here: "Turing equivalence fallacy" or perhaps "syntax sugar fallacy." All Turing Complete programming languages are Turing equivalent to one another. Programs written in one language can be mechanically transformed into those written in another. This is irrelevant to the discussion of programming l…

Of course the syntax sugar is a good thing if it makes it easier to write the code, but if the question is about "expressive power of the type system", it's not really relevant: Zig's type system can properly express a sum type. In addition: pattern matching is orthogonal to ADT, you can have pattern matching in both languages with and without algebraic types. Neither one implies the other.

> Zig's type system can properly express a sum type.

Surely any Turing complete PL can express a sum type? I can't imagine a language that can support products but not sums.

Re: Algebraic Data Types for C99

#107
post #97
post #81

Earlier quoted context omitted.

Sum types are disjoint unions. This `T` has three cases L = { tag: "a", payload: string } | { tag: "b", payload: number } R = { tag: "b", payload: number } | { tag: "c", payload: boolean } T = L | R whereas a proper sum type `L + R` would have four.

Isn't that a completely useless distinction? For all purposes and intents, the "b" type in L and R should be treated the same, no? What do you gain by not doing that??

This often comes up when writing a function which returns a wrapper over a generic type (like Option). If your Option type is T | null, then there's no way to distinguish between a null returned by the function or a null that is part of T.

As a concrete example, consider a map with a method get(key: K) -> Option. How do you tell the difference between a missing key and a key which contains `null` as a value?

Re: Algebraic Data Types for C99

#108
post #11
post #5

Interesting. Algebraic Data Types are almost always one of the things I miss when I use imperative languages. I have to do Java at work, and while I've kind of come around on Java and I don't think it's quite as bad as I have accused it of being, there's been several dozen instances of "man I wish Java had F#'s discriminated unions". Obviously I'm aware that you can spoof it with a variety of techniques, and often en…

Kotlin is JVM compatible and has ADTs. Java has https://github.com/functionaljava/functionaljava which is unsupported but stable.

Java 21's pattern matching (you don't need functionaljava, and shouldn't really use that unless you're really into FP) is kind of nicer than Kotlin's, because you can automatically "destruct" records in your matches.

For Java, see https://www.baeldung.com/java-lts-21-new-features

Kotlin's: https://www.baeldung.com/kotlin/when

Make up your own mind.

Re: Algebraic Data Types for C99

#109

One of the crimes of modern imperative programming languages is not having ADTs (except maybe Rust) built-in. It is such a basic mental model of how humans think and solve problems. But instead we got inheritance and enums which are practically very primitive.

C has always had them, it's called union. In practice you need to couple it with an enum, and your visitation mechanism is a switch statement. But C doesn't impose that on you and lets you do it as you see fit.

lol this is like saying C doesn't need structs, you can just declare the variables with a common prefix separately! See ma, product types!

Re: Algebraic Data Types for C99

#110

Earlier quoted context omitted.

You're approaching this from a PL design standpoint where the distinction is important, but from a user perspective it doesn't matter if it's just "syntax sugar" or if it's a super complicated to implement all that matters is whether the feature is available or not.

Typing features affect the way we design APIs. Libraries written in languages with type classes and without them can have completely different designs. If nested pattern matching is not available, this will not affect the APIs, only the function bodies -- because desugaring is local by definition.

Abstractly this is true, but software development is a human practice, so it matters not what's technically possible but what people actually do.

That's why the most important difference between C++ and Rust isn't some technicality even though the technical differences are huge, it's cultural. Rust has a Safety Culture and everything else is subservient to that difference.

Sugar matters, Rust's familiar looking loops are just sugar, it only "really" has a single way to do loops, the loop construct, an infinite loop you can break out of. But despite that, people deliberately write the other loops - and the linter strongly recommends that they write them, because the programs aren't just for machines to compile, they're for other humans to read, and a while let loop is an intuitive thing to read for example, so is the traditional for-each style iterator loop.

Post reply on HN