Live data from Hacker News

Names are not type safety

lexi-lambda.github.io

11–20 of 130 posts

Re: Names are not type safety

#11

> Newtypes are useful when carefully applied, but their safety is not intrinsic, no more than the safety of a traffic cone is somehow contained within the plastic it’s made of. What matters is being placed in the right context—without that, newtypes are just a labeling scheme, a way of giving something a name. What's a better alternative though? I like this approach for tagging e.g. user input that has been checked t…

It seems to me that there is no practical alternative. The impractical alternative is to extend the language so that its type system implements the feature you want. (For example, adding bounded integers.)

I don't see how that helps, though, because there could be bugs in your language extension, and it has to be maintained. It's just going about it the hard way. It would be sort of like avoiding "unsafe" in Rust by extending the compiler instead.

Re: Names are not type safety

#12
I disagree, and I think this kind of fundamentalism hurts the adoption of type safety. It's like saying that a non-machine-checkable mathematical proof is not a proof - something few working mathematicians would agree with.

In a well-formed program it is impossible to have a OneToFive that has not passed through toOneToFive. That's type safety by any reasonable definition. It's not as much type safety as you'd gain through explicitly modelling the internals, but that's a difference of degree, not kind. Sure, using `Generic` or any number of other things lets you break your rules - but so does using `unsafeCoerce` on the constructive version.

I'd argue that newtypes provide a better cost/benefit than essentially any other language feature. The author purports to embrace the idea that the type system is a tool to be used pragmatically, but that's exactly what using a newtype does: you enforce that appropriate checks are applied to any use of any given type, but what's "appropriate" is an internal concern for that module. Whereas expecting to be able to construct every domain datatype rigorously from first principles is simply not realistic in a lot of business cases; that constructive model may well be opaque or simply not exist for the domain you're working in. (Yes, this may well mean the domain you're working in is fundamentally incoherent - but if that incoherence is present in the real process that you're modelling, then your model has a responsibility to faithfully reproduce it).

This kind of newtype use can be done compositionally - one module can be reasoned about without needing to understand the internals of the modules you're depending on - which is the essence of practical, effective programming tools. A technique that only works in a "closed world" will always be severely limited in its applications.

Re: Names are not type safety

#13
(The following comment may not have anything to do with Haskell’s use of the word “name,” but I’ve wondered about this for a long time.)

Forcing someone to write iFoo instead of foo isn’t type safety, but it’s a certain kind of safety that I haven’t seen clearly spelled out. Actually I recall Joel on Software mentioning it once.

I don’t like it, but it’s always seemed interesting. Another example is in lisp:

  *current-input-port*
to indicate that a variable is dynamic, you can end it with an asterisk. But this is only a convention. I’ve always felt that LET should automatically do dynamic binding for any name that ends with . But then of course that runs into surprising corner cases when the user wants to e.g. write foo-+ foo-/ foo- foo—

You could argue that names aren’t type safety, but I would disagree that they aren’t any kind of safety. A good naming convention is one of the safest ways to program in an otherwise hostile domain. But that raises the question: what kind of safety is it? I’m not sure it even has a name, other than Hungarian notation, which is both imprecise and not sufficiently general for the concept.

EDIT: Ah, the post was “Making Wrong Code Look Wrong” by Joel on Software: https://www.joelonsoftware.com/2005/05/11/making-wrong-code-... (with discussion from 11mo ago: https://news.ycombinator.com/item?id=21482993)

The idea really should have a name.

Re: Names are not type safety

#14
post #10

> Newtypes are useful when carefully applied, but their safety is not intrinsic, no more than the safety of a traffic cone is somehow contained within the plastic it’s made of. What matters is being placed in the right context—without that, newtypes are just a labeling scheme, a way of giving something a name. What's a better alternative though? I like this approach for tagging e.g. user input that has been checked t…

In Haskell, you would use an algebraic data type that can only hold legal values. You would typically only use a newtype when you're just giving a new name to the same type. Having a Magnitude newtype over Int doesn't change the range of permissible values but does prevent using a Length where a Magnitude was expected, for example. In all typed languages you'll eventually see a function with multiple arguments of the…

Are you suggesting using Proxy to create a type that masks an Int?

How would you deal with text that can only contain certain characters for example?

Re: Names are not type safety

#15
post #5

Earlier quoted context omitted.

Applying the author's "parse, don't validate" concept, I think you'd parse the user input into a "safe HTML" type with a definition that excluded the language features that enabled those attacks. It might not be worth writing such code for a single project, but I could get behind a library that did that.

This is an approach I've used in C#/Java - you have 'UnvalidatedFoo' and 'ValidatedFoo' types, UnvalidatedFoo has a public constructor, ValidatedFoo has a private constructor. The only way to acquire a ValidatedFoo is to pass an UnvalidatedFoo into ValidateFoo(). The outer layer of the code deals in UnvalidatedFoos, but past that point you must have a ValidatedFoo to continue.

An extremely good example I've found for this is canonicalization in all forms. Frequently there are scenarios where there are many ways to represent something, but only one official Right Way.

https://en.wikipedia.org/wiki/Canonicalization#Usage_cases

Re: Names are not type safety

#16
post #12

I disagree, and I think this kind of fundamentalism hurts the adoption of type safety. It's like saying that a non-machine-checkable mathematical proof is not a proof - something few working mathematicians would agree with. In a well-formed program it is impossible to have a OneToFive that has not passed through toOneToFive. That's type safety by any reasonable definition. It's not as much type safety as you'd gain t…

> In a well-formed program it is impossible to have a OneToFive that has not passed through toOneToFive.

I think this is the key. In any (type) system, there’s an opportunity to chicanery the compiler. The degree to which you have to treat users of that system like children depends on how likely you think they are to behave badly.

If a “well-formed program” is something you can reasonably expect in your environment, you can also reasonably assume you also received a nominal type because it was validated. If it’s not, the expectation is that someone is lying to the compiler... and then you treat someone like they’re misbehaving. Even if they’re not.

Re: Names are not type safety

#17
post #7

Earlier quoted context omitted.

The article gives some examples why smart constructors don't fully solve the problem in the section "Newtypes as tokens"

Yeah, I don’t find those points very convincing. Obviously if you export other ways to construct the type, it doesn’t work... It’s like saying “if you forget to sanitize input it won’t get sanitized.” Okay?

The entire point of a good type system is to reduce the need for extra cognitive diligence around your data/code. The more corner cases you have to be careful around, the less helpful the type system is.

Re: Names are not type safety

#18
post #12

I disagree, and I think this kind of fundamentalism hurts the adoption of type safety. It's like saying that a non-machine-checkable mathematical proof is not a proof - something few working mathematicians would agree with. In a well-formed program it is impossible to have a OneToFive that has not passed through toOneToFive. That's type safety by any reasonable definition. It's not as much type safety as you'd gain t…

Read the article more carefully. I wrote in multiple places that the use of newtypes does provide real safety.

> If you are fond of newtypes, this whole argument may seem a bit troubling. It may seem like I’m implying newtypes are scarcely better than comments, albeit comments that happen to be meaningful to the typechecker. Fortunately, the situation is not quite that grim—newtypes can provide a sort of safety, just a weaker one.

> […]

> This tradeoff may not seem all that bad, and indeed, it is often a very good one! Guaranteeing invariants using constructive data modeling can, in general, be quite difficult, which often makes it impractical.

> […]

> Newtypes are useful when carefully applied

The whole point of the blog post is that newtypes are useful, but only when used in certain ways and in a weaker sense than constructive data modeling.

Re: Names are not type safety

#19
post #12

I disagree, and I think this kind of fundamentalism hurts the adoption of type safety. It's like saying that a non-machine-checkable mathematical proof is not a proof - something few working mathematicians would agree with. In a well-formed program it is impossible to have a OneToFive that has not passed through toOneToFive. That's type safety by any reasonable definition. It's not as much type safety as you'd gain t…

[deleted]

Re: Names are not type safety

#20

> Newtypes are useful when carefully applied, but their safety is not intrinsic, no more than the safety of a traffic cone is somehow contained within the plastic it’s made of. What matters is being placed in the right context—without that, newtypes are just a labeling scheme, a way of giving something a name. What's a better alternative though? I like this approach for tagging e.g. user input that has been checked t…

> What's a better alternative though?

I’m not really suggesting there needs to be an alternative. Using newtypes to achieve safety via encapsulation is fine, good even, and I say as such at several points in the article.[1] The point is twofold:

1. A lot of uses of newtypes in the wild are “safety theater” and provide zero actual safety benefit.

2. The uses of newtypes that do add safety provide it in a weaker sense than correct-by-construction data modeling.

The point is not that newtypes are always useless. In fact they are often by far the most practical tool for the job. The blog post just advocates being conscious and considerate of the limitations of the techniques.

[1]: https://news.ycombinator.com/item?id=24964494

Post reply on HN