HNHacker News
TopNewBestAskShowJobs

ackfoobar

713 karma · joined April 26, 2021

submissionscomments
ackfoobar··on OCaml as my primary language
> straight/naive rewrite was ~3 times faster

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.

ackfoobar··on OCaml as my primary language
PS rereading this I think "hope you're a Haskeller" might be read as an insult. That's not my intention, here's why I mention Haskell.

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.

1: https://ocsigen.org/js_of_ocaml/toplevel/

2: https://xkcd.com/386/

ackfoobar··on OCaml as my primary language
Since the cardinalities match the algebra, it's no surprise that identities translate, but seeing them still brings a smile to my face.

The correspondence can be pushed much further - to differentiation!

https://codewords.recurse.com/issues/three/algebra-and-calcu...

ackfoobar··on OCaml as my primary language
> I'm not sure why

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.

ackfoobar··on OCaml as my primary language
> Substantiate this.

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.

ackfoobar··on OCaml as my primary language
You wrote a lot of words to say very little.

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://news.ycombinator.com/item?id=24203363

ackfoobar··on OCaml as my primary language
Yes

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

ackfoobar··on OCaml as my primary language
> So i am not sure why we are arguing :)

I think we agree on a lot of points. The rest is mostly preferences. Some other comments in my thread though...

ackfoobar··on OCaml as my primary language
Oh if you use those features to express what "sum type as subtyping" can, it sure gets confusing. But it's not those things that I want to express that are hard to reason about, the confusing part is the additions to the HM type system.

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.

ackfoobar··on OCaml as my primary language
Good point, well there's Ordering type built-in in Haskell (LT | EQ | GT). Ordering -> bool has 2^3=8 values (const true, const false, == LT, == EQ, == GT, is_lte, is_gte, ne)

EDIT: now you see why I used the smallest type possible to make my point. Exponentials get big FAST (duh).

ackfoobar··on OCaml as my primary language
A first-order function type is already exponential.

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.

ackfoobar··on OCaml as my primary language
> The moment you start ripping cases as distinct types out of the sum-type, you create the ability to side-step exhaustiveness and sum-types become useless in making invalid program states unrepresentable.

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?

ackfoobar··on OCaml as my primary language
If you don't do inline records you either

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

ackfoobar··on OCaml as my primary language
> the end result is seriously faster

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.

ackfoobar··on OCaml as my primary language
Unless you reach an unsound part of the type system I don't see how. Could you provide an example?
ackfoobar··on OCaml as my primary language
> I have no idea

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.

ackfoobar··on OCaml as my primary language
> Just ugliness and typical boilerplate heavy approach of JVM languages.

I have provided a case how using inheritance to express sum types can help in the use site. You attacked without substantiating your claim.

ackfoobar··on OCaml as my primary language
> Sum types: For example, Kotlin and Java (and de facto C#) use a construct associated with inheritance relations called sealing.

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.

ackfoobar··on Byte Buddy is a code generation and manipulation library for Java
> If you want speed

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

ackfoobar··on Byte Buddy is a code generation and manipulation library for Java
As a Kotlin enjoyer, I find these comments counterproductive. Maybe they like the lack of extension functions?
ackfoobar··on GitHub is no longer independent at Microsoft after CEO resignation
> .NET is now cross platform, but only as long as it doesn't hurt VS sales, with GUI workloads, profilers, still being mostly Windows only, and partially supported on VSCode, which also has the same VS license.

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?

ackfoobar··on I bought a £16 smartwatch just because it used USB-C
> The watch is simply missing the two 5.1k resistors connecting the CC1 and CC2 pins of the USB-C connector to ground that are required to indicate to whatever is plugged in that it wants 5v power.

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.

ackfoobar··on Why F# could be the next mainstream programming language (2024)
> Give it a script

Ideally the build tool does that for you, e.g. `./gradlew run -t`.

ackfoobar··on Researchers map where solar energy delivers the biggest climate payoff
> things that are a net improvement do not preclude other things that are net improvements.

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.

ackfoobar··on Researchers map where solar energy delivers the biggest climate payoff
A diesel train releases orders of magnitudes less CO2 than flights though.
ackfoobar··on Python classes aren’t always the best solution
> dataclasses are, um, classes

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.

ackfoobar··on Python classes aren’t always the best solution
Pydantic is everything I want Python dataclasses to be.

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.

ackfoobar··on There is no memory safety without thread safety
Do you have some examples? I think JDK developers make a lot of effort to make sure users bugs will not corrupt the runtime.
ackfoobar··on Major rule about cooking meat turns out to be wrong
I'm shooting for 54C medium rare but I've never left a thermometer to see the temp rise and fall. The steaks taste good is all I can tell you.
ackfoobar··on Major rule about cooking meat turns out to be wrong
I agree that his suggestion is more applicable to home cooks than restaurants.
← PreviousPage 2 of 13Next →