How much of that do you think comes from reduced allocations/indirections? Now I really want to try out OxCaml and see if I can approximate this speedup by picking up low hanging fruits.
713 karma · joined April 26, 2021
How much of that do you think comes from reduced allocations/indirections? Now I really want to try out OxCaml and see if I can approximate this speedup by picking up low hanging fruits.
1. It's THE other language with a type system based on HM.
2. Variant constructors as functions. OCaml does not do that, Haskell does (slightly more elegant). This hints sunnydiskincali is more familiar with Haskell than OCaml.
3. I was confused by `type shape = S.shape`. How does `RemovePoint(Shape).shape` has the `Point` case removed then? I tried that on a REPL ^1 and it didn't even compile. Again, syntax errors hinting at Haskell experiences.
Well now I've written so much I may as well do a point-by-point refutation: ^2
> you create the ability to side-step exhaustiveness
Big claim, sounds scary to someone not familiar with sum types. But Java/Kotlin both enforce exhaustiveness. You could have provided an example in your second response, instead you dump a bunch of code that does not compile.
> Sure you can, that's just subtyping.
Then you followed up with an example that is not subtyping, but an unrelated type of a new set of new values.
> This is doing things quick and dirty. For this trivial example it's fine
This is not fine. I undersold the verbosity of your "quick and dirty" solution saying "7 lines". To actually work with those two types, the pair of conversion functions `Shape.shape -> Bound.shape option` and `Bound.shape -> Shape.shape` is needed.
> They're not similar at all.
~100 words in the paragraph, gestures to formalization, yet never explained how sum types implemented as sealed inheritance cannot be "enforcing valid program-states at a type-level". Thus my comment "a lot of words to say very little".
> You're still creating a type
I see you removed "unrelated" in an edit. The statement is now accurate but pointless. Of course I need to create a type, how else can I use the type system to say "this function won't return a point"?
> disingenuous to imply the quotation means that the type-system in Java ... was lifted from ML.
It would be more than disingenuous, colossally stupid even, if I did imply that. The wrongness would be on the level of claiming "English and Japanese are in the same language family".
Your cognate/false friend analogy is much smaller in scope, just like Java taking sum types (implementing them as sealed inheritance) from ML.
The correspondence can be pushed much further - to differentiation!
https://codewords.recurse.com/issues/three/algebra-and-calcu...
Me neither.
> you are entirely correct that sealed types can fully model sum types
I want to be wrong, in that case I learn something new.
You never gave an example how sum types in Java/Kotlin cannot do what "real" sum types can.
>> weird name choice but whatever
> snarky potshot
Sorry that you read snark. What I meant was "I find naming this 'Bound' weird. But since I am translating your example, I'll reuse it".
> You're still creating an unrelated type
How can a type participating in the inheritance hierarchy be "unrelated"?
> I see the same degree of contortion, actually. Far more noisy, at that.
At this point I can only hope you're a Haskeller and do not represent an average OCaml programmer.
Anyway, to translate your example:
sealed interface Shape permits Point, Bound {}
final class Point implements Shape {}
sealed interface Bound extends Shape permits Circle, Rectangle {}
record Circle(double radius) implements Bound {}
record Rectangle(double width, double height) implements Bound {}
A `Rectangle` is both a `Bound` (weird name choice but whatever), and a `Shape`. Thanks to subtyping, no contortion needed. No need to use 7 more lines to create a separate, unrelated type.> the Japanese word for "name" sounds like the English word, despite not being a loan word.
Great analogy, except for the fact that someone from the Java team explicitly said they're drawing inspirations from ML.
https://openjdk.org/jeps/409#Sealed-classes-and-pattern-matc...
> with pattern matching for switch (JEP 406)the compiler can confirm that every permitted subclass of Shape is covered, so no default clause or other total pattern is needed. The compiler will, moreover, issue an error message if any of the three cases is missing
I think we agree on a lot of points. The rest is mostly preferences. Some other comments in my thread though...
A meta point: it seems to me that a lot of commenters in my thread don't know that vanilla HM cannot express subtypes. This allows the type system to "run backwards" and you have full type inference without any type annotations. One can call it a good tradeoff but it IS a tradeoff.
EDIT: now you see why I used the smallest type possible to make my point. Exponentials get big FAST (duh).
A sum type has as many possible values as the sum of its cases. E.g. `A of bool | B of bool` has 2+2=4 values. Similarly for product types and exponential types. E.g. the type bool -> bool has 2^2=4 values (id, not, const true, const false) if you don't think about side effects.
Quite the opposite, that gives me the ability to explicitly express what kinds of values I might return. With your shape example, you cannot express in the type system "this function won't return a point". But with sum type as sealed inheritance hierarchy I can.
> C#/Java don't actually have sum-types.
> They're pretty much the same
Not sure about C#, but in Java if you write `sealed` correctly you won't need the catch-all throw.
If they're not actual sum types but are pretty much the same, what good does the "actually" do?
- create a separate record type, which is no less verbose than Java's approach
- use positional destructuring, which is bug prone for business logic.
Also it's funny that you think OCaml records are "with better syntax". It's a weak part of the language creating ambiguity. People work around this qurik by wrapping every record type in its own module.
https://dev.realworldocaml.org/records.html#reusing-field-na...
Do you have a ballpark value of how much faster Rust is? Also I wonder if OxCaml will be roughly as fast with less effort.
I can tell.
Thankfully the OCaml textbook has this explicitly called out.
https://dev.realworldocaml.org/variants.html#combining-recor...
> The main downside is the obvious one, which is that an inline record can’t be treated as its own free-standing object. And, as you can see below, OCaml will reject code that tries to do so.
I have provided a case how using inheritance to express sum types can help in the use site. You attacked without substantiating your claim.
This has the benefit of giving you the ability to refer to a case as its own type.
> the expression of sums verbose and, in my view, harder to reason about.
You declare the sum type once, and use it many times. Slightly more verbose sum type declaration is worth it when it makes using the cases cleaner.
> If you want to be efficient
Funny that you assume the best position of the trade off continuum isn't somewhere in the middle for most people. Besides, for developer efficiency, I prefer a language where I don't have to constantly worry if the type system is defeated at runtime.
On HN I keep hearing that associating .NET with Windows is outdated perception.
Writing JVM languages I feel that the developer experience is pretty much the same on any OS. It seems this cannot be said for .NET?
This is so annoying. Back when USB-C was less prevalent, I bought a pair of wireless earbuds over another for the same reason as the title - because it used USB-C. But then I cannot charge it with my macbook, unless I add a USB-C to USB-A adapter.
Ideally the build tool does that for you, e.g. `./gradlew run -t`.
That's a good framework to think about things. Going all-in on renewables implies keeping fossil fuels around, because storage tech is several breakthrough behind. Renewable proponents like to point out that every kWh not produced with CO2 emission is still a win.
Yet deploying renewables means they flood the market with cheap electricity when the weather is good, hurting the profit, thus viability, of (i.e. precluding) stable low-carbon sources (in other words I'm butt hurt about nuclear).
> The vast majority of offsetting schemes are little more than accountability laundering and on-paper games, not translating to any concrete offsetting in the real world.
A case I heard is that they count the carbon captured by planting trees, yet ignore it when the carbon is released back to the atmosphere in a wildfire.
So is the case when you use `namedtuple`, which creates a new class. This is not an interesting gotcha.
Classes (the Python language construct) are how you implement records (the language-neutral concept) in Python.
It's ironic that the "There Is Only One Way to Do It" language has multiple bad ways to implement records though.
While Pydantic `BaseModel`s, like dataclasses, are still "classes", I consider that an implementation detail of how records are implemented in Python - thus not really contradicting the article's recommendation against using a class.