Live data from Hacker News

Types as Interfaces

two-wrongs.com

101–110 of 197 posts

Re: Types as Interfaces

#101

Earlier quoted context omitted.

What, to you, is an ultra strong type system? Both OCaml and Haskell are used in plenty of non academic contexts. Do you mean something like Coq or F*?

"plenty" is relative. You don't see many GAFAM products created in either, and that's because of the trade off OP talks about.

I don't see many GAFAM products created in any functional language, even those with primitive type systems. Are you sure it is the type system that is scaring people away?

Re: Types as Interfaces

#102
post #30
post #19

Earlier quoted context omitted.

The Ceylon language allowed you to do that sort of thing with types. If you "added" two maps together of types `Map ` and `Map `, you would get back a `Map ` (or, equivalently, `Map | Map `). But for some slightly complex reasons, most language designers find adhoc union types (which are required for this to work) a bad idea. See the Kotlin work related to that, they explicitly want to keep that out of the language (…

> If you "added" two maps together of types `Map ` and `Map `, you would get back a `Map ` (or, equivalently, `Map | Map `). But these are obviously not equivalent: the first type is a map where all values are either strings or ints, and the second one is either a map where all values are strings, or all values are ints. If that's confusing, consider: {foo: 1, bar: "2"}. It satisfies `Map ` but not `Map | Map `. (In…

These types are equivalent if you consider a value of both of these types have the exact same read operations. Calling `get(String)` will return `String | int` in both cases. You're right that you could build a value of one of these types that does NOT conform to the union, however. I am not sure what's the technical name for what I am trying to say... are they "covariantly equivalent"???

EDIT: ok, I just wanted to say that one type, `Map`, is a supertype of `Map | Map`, so if a function accepts the former, it also accepts the latter. They're not equivalent but you can substitute one for the other (one way only) and still perform the same operations (always assuming read-only types, if you introduce mutation everything becomes horrible).

I was trying to emphasize how having type "combinations" ends up causing the type system to become undecidable as you end up with infinite combinations possible, but as I haven't really gone too deeply into why, I am having trouble to articulate the argument.

Re: Types as Interfaces

#103

Earlier quoted context omitted.

Typescript also does the former, albeit with less friendly syntax. X: 1 | 2 | 3 // …

Kinda but not really. It actually handles type inference on string concatenation, but doesn't understand math. type N = 1 | 2 const x1:N = 1 const x2:N = 1 const sum:N = x1 + x2 Typescript (the version running on my box) considers this an error.

There is nothing to suggest that 1..100 understands math.

Re: Types as Interfaces

#104

I’ve come to believe that a type should be capable of reflecting any arbitrary rules a programmer knows about the bounds of a value. The only real implementations of this I see are mostly academic with a dependent type system like Idris. We’re many years from that becoming mainstream, if it ever will be.

I wish it were possible, but I have a sneaking suspicion that types like PrimeNuber or TotalProgram, are beyond the realm of possibility.

Re: Types as Interfaces

#105

I’ve come to believe that a type should be capable of reflecting any arbitrary rules a programmer knows about the bounds of a value. The only real implementations of this I see are mostly academic with a dependent type system like Idris. We’re many years from that becoming mainstream, if it ever will be.

Requirements change, things evolve. Having bounds in the type system is too restrictive.

Even history of "required", rather simple restriction on the value, is showing that putting that logic into type system is too much of a burden.

https://capnproto.org/faq.html#how-do-i-make-a-field-require...

Re: Types as Interfaces

#106
post #87

Earlier quoted context omitted.

Elixir is taking a similar direction if I'm understanding correctly (they seem to insist their type system is fundamentally from Typescript's, but to this day I cannot understand how, both are structural and based on set theory)

Is elixir's type system sound?

The type system is still in development so we haven't seen what the end result is yet, but I believe the system they're implementing is going to be sound.

Re: Types as Interfaces

#107

I’ve come to believe that a type should be capable of reflecting any arbitrary rules a programmer knows about the bounds of a value. The only real implementations of this I see are mostly academic with a dependent type system like Idris. We’re many years from that becoming mainstream, if it ever will be.

I agree with the philosophy at a high level, but opening up the power of what you can do at compile time is a very deep and nuanced trade off space. I think there’s a more general way to state what you’re getting after as well: we should be able to express arbitrary constraints that are enforced by the compiler. These constraints don’t really have to be about values themselves but could also be about how they are consumed e.g. linear types.

Unfortunately, the more powerful the type system, the harder it is to make inferences. Generality comes at a cost.

Re: Types as Interfaces

#108
post #23

types are not interfaces. interfaces describe behavior, types describe shape and structure. the difference is subtle but important.

Depends on the language. In typescript and interface can absolutely encode shape. In C# you can encode shape in interfaces via properties. Interfaces don’t even describe behavior, it’s just that we typically associate them with a man implicit contract. Strictly speaking they are just a shape.

Re: Types as Interfaces

#109
post #77

I’ve come to believe that a type should be capable of reflecting any arbitrary rules a programmer knows about the bounds of a value. The only real implementations of this I see are mostly academic with a dependent type system like Idris. We’re many years from that becoming mainstream, if it ever will be.

I regret to say that every type level Gordian knot that I have ever been exposed to came from attempts to do this. I think a lot of the problem is that many of the constraints and acceptable values for data are not determined until well after first deployment. The "knot" comes in when you are explicitly changing data and code to add a feature that you didn't anticipate at the start. This is a lot like schemaless data…

>> This is a lot like schemaless databases. The flexibility of not having to fully specify the full schema does not mean that you don't benefit from specifying parts of it? Indeed, if you are indexing things, you have to specify those parts. But it is hard to argue with a straight face that schemaless tools don't have some strong benefits.

This is very similar to what Rich Hickey argued in "Simplicity Matters": https://youtu.be/rI8tNMsozo0?si=xTkpsLYTYh0jA5lB

Basically when you use a hash / JavaScript-style object rather than a fixed struct definition for your data (which amounts to a schema- less database in aggregate)

    Easy addition of new properties

    Co-existence of different versions of objects (newer objects will typically have more properties)

    Introspection of properties and validation rules / reflection

Re: Types as Interfaces

#110
This is a lot of complication for in what most OOP languages with interfaces would simply be something like:

    interface Timestamped {
      timestamp: UTCTime;
    }
    interface Msg {
      sender: PlayerId;
    }
    class Quote implements Timestamped, Msg {
      timestamp: UTCTime;
      sender: PlayerId;
    }
Why is this so hard in Haskell? It doesn't have interface polymorphism?
Post reply on HN