Live data from Hacker News

Don't use booleans (2019)

luu.io

101–110 of 152 posts

Re: Don't use booleans (2019)

#101
post #92

I interpreted this as 'don't write crappy functions taking confusing arguments'. If the function had taken 4 floating point numbers, the argument would be the same - it would be confusing to know what is what.

Sure, but booleans are the lowest hanging fruit, most programmers won't write many functions which take 3 floating point numbers and are then modified to add a fourth but they will write functions which have three flag booleans and then add a fourth.

The generalization of the author's lesson is the New Type idiom. Don't use basic types like "integer" when you can invent types which correspond to the actual meaning of your values. A Duration, a FileDescriptor, a DatabaseHandle, a KeyboardScanCode. Once we do this it's obvious that if the function takes a FileDescriptor and a Duration we should not give it this KeyboardScanCode we have twice, that's clearly nonsense.

Rust piles on extra value for its own New Types (as yet you cannot directly grant this to your own types although if they're enumerations they get it for free) - niches. Result is the same size (a single 32-bit integer) as the C int you'd have used for this purpose in a much less capable language, but since it's a Result type it has all the same ergonomics as if it was much more complicated and heavyweight than that.

Re: Don't use booleans (2019)

#103

Earlier quoted context omitted.

TypeScript enums, from personal experience, should be avoided in cases where the value is stored. The reason is that the compilation from `SomeEnum` to JS involves conversion to an object indexer[0]. Should you, in the future, need to (or accidentally) remove or change an enum option, this will fail with an index out of range exception at runtime that is not obvious to track down. Put it another way: it leaves behind…

Sorry, can you explain this more? I somehow still don't understand. How is this different from a const object style enum? Or are you more referring to the sum type enum as the better choice here to avoid this. Generally, if you remove an enum variant, the compiler should warn you if you've used it anywhere else (though of course it can't figure out a dynamic usage)... But this seems like a problem mostly for dynamic…

My understanding of the comment is that it’s in the context of saving an enumeration-object into a database.

Like Typescript might (for example) represent enums as integers like 1, 2, 3... at runtime.

What happens if you decide to store a “delivery status” enum in a database? You would just be saving a number into the database, which can be hard to understand.

If it’s a string, then the value stored in the database is clearer and doesn’t depend on you being lucky with the Typescript compiler that the same enum type is compiled to the same integers after new releases.

I only realised this issue now, but it’s what I understood after reading that comment.

Re: Don't use booleans (2019)

#104
post #91

Earlier quoted context omitted.

An Option has the advantage that you con chain it with other Option/Result operations like map, and_then, etc. I think this would be called being "monadic". The advantage of Enum with Missing variant is that it's more expressive, and that you don't have to nest access in the Some matching. Generally I prefer Option , and often you can match directly with Some(Variant) to avoid nested matches.

> map, and_then, etc. I think this would be called being "monadic". Strictly speaking, I think providing "map" just makes it functorial. Monadic would need a flatmap. (In addition to the other functor and monad requirements, of course.)

So what would you call something like "it implements some common operations", like these?

For example, the Option and Result type both have functions like "map", they do the same thing just on different types. They're not quite generic in that sense, but on a high level they seem so.

Another example are reactive libraries. Everything is pegged into some common operations like map, take, and so on.

Re: Don't use booleans (2019)

#105

Earlier quoted context omitted.

TypeScript enums, from personal experience, should be avoided in cases where the value is stored. The reason is that the compilation from `SomeEnum` to JS involves conversion to an object indexer[0]. Should you, in the future, need to (or accidentally) remove or change an enum option, this will fail with an index out of range exception at runtime that is not obvious to track down. Put it another way: it leaves behind…

Sorry, can you explain this more? I somehow still don't understand. How is this different from a const object style enum? Or are you more referring to the sum type enum as the better choice here to avoid this. Generally, if you remove an enum variant, the compiler should warn you if you've used it anywhere else (though of course it can't figure out a dynamic usage)... But this seems like a problem mostly for dynamic…

    but in the code I've written so far trying to construct the the enum object almost always consisted of using a function to validate anyway
It's exactly this problem and it's not obvious for someone choosing an enum type that the underlying implementation in JS is an object indexer.

Re: Don't use booleans (2019)

#106

Earlier quoted context omitted.

Sorry, can you explain this more? I somehow still don't understand. How is this different from a const object style enum? Or are you more referring to the sum type enum as the better choice here to avoid this. Generally, if you remove an enum variant, the compiler should warn you if you've used it anywhere else (though of course it can't figure out a dynamic usage)... But this seems like a problem mostly for dynamic…

My understanding of the comment is that it’s in the context of saving an enumeration-object into a database. Like Typescript might (for example) represent enums as integers like 1, 2, 3... at runtime. What happens if you decide to store a “delivery status” enum in a database? You would just be saving a number into the database, which can be hard to understand. If it’s a string, then the value stored in the database i…

This is also another problem and a reason to strictly stick to string type unions, IMO.

There may be a really good use case for the enum type, but I think in most cases, string type unions are clearer, easier, and less prone to errors.

Re: Don't use booleans (2019)

#108
One more benefit to favor enums for booleans here. When passing facts/intent solely through a generic true/false, and possible a single more or less well-named identifier, you have increased risk of multiple and differing interpretations of what the values mean: Did 0 or 1 mean failure or success? did false mean that the file did not exist or that you are not allowed to access it? By explicitly naming what your 'true' and 'false' cases mean, you _can_ lessen this risk. (Of course, you can still communicate badly both with booleans and with badly named enums.) Also for return values for functions, you don't have an identifier name (not all acting functions share name with their "report-back"). Further, enums _may_ upgrade elegantly when you learn your boolean assumption had >2 cases.

I read about half of of submissions, I don't know if others also said all this already.

Re: Don't use booleans (2019)

#109

One more benefit to favor enums for booleans here. When passing facts/intent solely through a generic true/false, and possible a single more or less well-named identifier, you have increased risk of multiple and differing interpretations of what the values mean: Did 0 or 1 mean failure or success? did false mean that the file did not exist or that you are not allowed to access it? By explicitly naming what your 'true…

caveat: In languages where enums silently accept random ints, they break this somewhat, sadly.

Re: Don't use booleans (2019)

#110

This goes away in a language that allows arguments to name the parameters: fetch(accountId, history = true, details = false); However, I would be opposed if this mechanism is permitted to perturb the order of fixed arguments. If history is the third argument, rather than the second, it should error. I.e. "history = true" means "we are passing true as the second parameter, which we believe to be called 'history', on p…

Is this an example from some well-known compiled language?

I work mostly in C++, and this is a feature I've wished for for a long time.

Post reply on HN