Live data from Hacker News

Types as Interfaces

two-wrongs.com

121–130 of 197 posts

Re: Types as Interfaces

#121
post #43

Indeed, TypeScript can do exactly this and more, without much ceremony: type FooBar = Foo & Bar I doubt you will find a language where it is less clunky. Edit: Oh, I typed this on mobile, this was supposed to be a comment on another comment by posix_monad.

Foo and Bar are now compatible with FooBar which can create a lot of issues even in strict mode. Typescript is amazing, but interfaces not being struct are a footgun in many places

What issues?

Re: Types as Interfaces

#122

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'm surprised that most popular languages don't even do simple type constraints. Like x: 1..100 y: "yes" | "no" I feel that there are lots of low hanging fruits when it comes to typing which would improve both program readability and correctness.

In the type-theoeretic world, you want to refer to "refinement types" [0]. Some interesting work that I have seen in this direction is Liquid Types [1][2]. There is some work in Haskell[3], but it is surprisingly very useful in Rust as well.

[0] https://en.wikipedia.org/wiki/Refinement_type [1] https://goto.ucsd.edu/~ucsdpl-blog/liquidtypes/2015/09/19/li... [2] https://goto.ucsd.edu/~rjhala/liquid/liquid_types.pdf [3] https://ucsd-progsys.github.io/liquidhaskell/ [4] https://github.com/flux-rs/flux

Re: Types as Interfaces

#124
post #90
post #80

Earlier quoted context omitted.

The problem is that user inferring doesn't scale. For small projects this is reasonable but for enterprise software engineering it is easy for a constraint that isn't enforced by the type system to be missed by an engineer leading to a bug. Whereas typed constraints naturally propagate throughout the system.

Yeah - in theory they are the same thing. You can have a dependent type that's an array with a length of 5 or you can create a type called ArrayLengthFive, and in both cases the type checker ensures that you don't accidentally use an unbounded array. But the difference is that with a dependent type, you get more guarantees (e.g. my ArrayLengthFive type could actually allow for arrays of length 20!). And the type chec…

> In the string -> Email example, it's probably enough to parse your string and just call it an email. You don't need to try to encode all the rules about an email into the type itself.

There is also the in-between Rust approach. Start with the user input as a byte array. Pass it to a validation function, which returns it encapsulated within a new type.

    #[derive(Clone, Hash, Ord, Eq...)]
    struct Email(Box);

    // validate UTF-8 + 
    fn validate(raw: &[u8]) -> Result;
What is annoying is the boilerplate required. You usually want your new type to behave like a (read-only) version of the original type, and you want some error type with various level of details.

You can macro your way out of most of the boilerplate, with the downside that it quickly becomes a domain specific language.

Re: Types as Interfaces

#125

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.

PrimeNumber is definitely possible in pretty much any dependent type language. Indeed, it would be pretty impossible to get any work done in Lean without it.

TotalProgram: possible in some, not in others, I think.

Re: Types as Interfaces

#126
post #43

Indeed, TypeScript can do exactly this and more, without much ceremony: type FooBar = Foo & Bar I doubt you will find a language where it is less clunky. Edit: Oh, I typed this on mobile, this was supposed to be a comment on another comment by posix_monad.

Foo and Bar are now compatible with FooBar which can create a lot of issues even in strict mode. Typescript is amazing, but interfaces not being struct are a footgun in many places

[dead]

Re: Types as Interfaces

#127
post #89

Earlier quoted context omitted.

Slightly more optimistically: As we go along, small pieces go from "too expensive to actually use" to "usable on real projects, but nobody does yet", and then to "doesn't everybody do that?" This is the story of improvements in type systems over the last 70 years. But the progress is very slow. So this is only slightly more optimistic...

This is where I'd really be interested in seeing an AI system help. Don't write an AI system that helps me shovel out vast quantities of code, and then solves the problem of the resulting incomprehensible mass of code being impossible to work with by making it even easier to shovel out yet more masses of code to deal with the even larger masses of AI-generated code. It does not take a genius to see that this ends up…

I think the world of datalog and dynamic logic programming (or perhaps Answer Set Programming with Constraints) may be very useful in scenario 2, and people are still pursuing that without waiting for scenario 1 to happen first.

Yeah, scenario 1 will also probably still happen.

Re: Types as Interfaces

#128
post #86

Earlier quoted context omitted.

How would you ensure that the values of the types doesn't invalidate the contract? Easy for basic assignment, but not sure how you would do that when doing arbitrary mutation.

You could prevent arbitrary mutation, pushing computation onto a more flexible type and allowing assignment back to the more constrained type only when first guarded by an appropriate conditional. The whole "parse, don't validate" thing.

The reference (an excellent read!): "Parse, don't validate" https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...

Re: Types as Interfaces

#129

Earlier quoted context omitted.

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

Sometimes I’ve wondered if versioned types might be a help in bringing coexistence to a typed setup, and if this is part of where the benefits of a service oriented architecture come from. But given how versioning snarls can play out in dependency management I expect this idea has some tradeoffs in the best case.

I'm curious what you have in mind that doesn't boil down to "duck typing?"

Re: Types as Interfaces

#130
post #90

Earlier quoted context omitted.

Yeah - in theory they are the same thing. You can have a dependent type that's an array with a length of 5 or you can create a type called ArrayLengthFive, and in both cases the type checker ensures that you don't accidentally use an unbounded array. But the difference is that with a dependent type, you get more guarantees (e.g. my ArrayLengthFive type could actually allow for arrays of length 20!). And the type chec…

> In the string -> Email example, it's probably enough to parse your string and just call it an email. You don't need to try to encode all the rules about an email into the type itself. There is also the in-between Rust approach. Start with the user input as a byte array. Pass it to a validation function, which returns it encapsulated within a new type. #[derive(Clone, Hash, Ord, Eq...)] struct Email(Box ); // valida…

AKA the "parse, don't validate" approach [1].

1: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...

Post reply on HN