Live data from Hacker News

Don't use booleans (2019)

luu.io

91–100 of 152 posts

Re: Don't use booleans (2019)

#91

Tangentially -- use languages that have great enum support. Well you knew what was coming -- Rust enums are excellent[0], and so are Haskell's[1] (try and spot the difference between an enum and a record type!)... But that probably won't help you at $DAYJOB. A bit more on topic though -- I'd like to see a strong opinion on Option versus SomeEnum containing a Missing variant. I usually lean towards Option but I wonder…

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

Re: Don't use booleans (2019)

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

Re: Don't use booleans (2019)

#93

Earlier quoted context omitted.

Typescript is great for this. function operation(user: User, state: “active” | “inactive”): void Boom. Done. Enum defined. You want people to use enums? Remove all context switching from the definition process.

Ah I love Typescript (IMO JS is the best "scripting language" out there, and has been for a very long time, but that's a different discussion). That said, I hate that typescript has many ways of doing it. That's the biggest problem. There's: enum SomeEnum { First, Second, } const enum SomeConstEnum { A = 1, B = A * 2, } type SomeEnumType = "first" | "second"; const SomeObjectThatIsAnEnum = { "first": 1 "second": 2 }…

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 an artifact in the output JS that can be a source of exceptions.

[0] https://www.typescriptlang.org/play/?ssl=5&ssc=2&pln=1&pc=1#...

Re: Don't use booleans (2019)

#94

Tangentially -- use languages that have great enum support. Well you knew what was coming -- Rust enums are excellent[0], and so are Haskell's[1] (try and spot the difference between an enum and a record type!)... But that probably won't help you at $DAYJOB. A bit more on topic though -- I'd like to see a strong opinion on Option versus SomeEnum containing a Missing variant. I usually lean towards Option but I wonder…

Option is the better of the two. With a missing variant, there's no way to encode "infallibly successful". All call sites would have to check for a missing variant in all cases.

Re: Don't use booleans (2019)

#95
post #84

Tangentially -- use languages that have great enum support. Well you knew what was coming -- Rust enums are excellent[0], and so are Haskell's[1] (try and spot the difference between an enum and a record type!)... But that probably won't help you at $DAYJOB. A bit more on topic though -- I'd like to see a strong opinion on Option versus SomeEnum containing a Missing variant. I usually lean towards Option but I wonder…

> I'd like to see a strong opinion on Option versus SomeEnum containing a Missing variant. Java $DAYJOB here. If I'm a caller, I probably won't realise that SomeEnum.Missing exists. I'll just see that a function accepts a SomeEnum (which I don't have) so I won't call it.

This is a good point -- Optionis much better in a fn signature for comprehension. This probably clinches it.

Funnily enough, Java 1.8 is what really made me start taking Haskell and languages with better type systems more seriously -- seeing that Option actually deserved to be basically everywhere broke my frame.

Re: Don't use booleans (2019)

#96

Earlier quoted context omitted.

Ah I love Typescript (IMO JS is the best "scripting language" out there, and has been for a very long time, but that's a different discussion). That said, I hate that typescript has many ways of doing it. That's the biggest problem. There's: enum SomeEnum { First, Second, } const enum SomeConstEnum { A = 1, B = A * 2, } type SomeEnumType = "first" | "second"; const SomeObjectThatIsAnEnum = { "first": 1 "second": 2 }…

Typescript type system is probably gold standard, you can enforce so much statically

As far as gold standards go for typesystems... ML languages probably take it, with Haskell being the closest to widespread real world use.

Re: Don't use booleans (2019)

#97
I haven't seen it mentioned elsewhere in this thread, but I really appreciated my IDE adding extra information in function calls, annotating create(true, false) into create(initial_state: true, reset: false)

Re: Don't use booleans (2019)

#98

Earlier quoted context omitted.

Ah I love Typescript (IMO JS is the best "scripting language" out there, and has been for a very long time, but that's a different discussion). That said, I hate that typescript has many ways of doing it. That's the biggest problem. There's: enum SomeEnum { First, Second, } const enum SomeConstEnum { A = 1, B = A * 2, } type SomeEnumType = "first" | "second"; const SomeObjectThatIsAnEnum = { "first": 1 "second": 2 }…

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 code, where you'd probably write some sort of Enum.parse() or Enum.from() static method anyway?

If I'm understanding your comment correctly, the real problem is that when you store the value, remove one, and try to read it back out into the enum it will fail - 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, these days I use zod but before I'd write stuff like:

    function isEnum(obj: unknown): obj is Enum {
      return obj && typeof obj === 'string' && Object.values(Enum).includes(obj)
    }

Re: Don't use booleans (2019)

#99
post #41

You can think of booleans as a built-in, two-value enum that has a common semantic meaning. Use booleans if this is suitable for your purpose; it will be suitable for many. That said... this article feels like a bit of a strawman. Does anyone by default use three booleans in cases that are arechetypical enums?

It usually starts with "is_car", a simple, clear, yes or no. and then at some point someone needs to also check if it's a sedan and instead of turning it into an enum called vehicle_type an "is_sedan" is added, etc.

The other side of the coin is making an enum and eventually realizing that some of the types can overlap. I prefer the "set of tags" approach due to its flexibility.

Re: Don't use booleans (2019)

#100
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.)

You're right, and I'd add on that monads only need pure and bind (>>=), das it!

    pure :: Monad m => a -> M a

    (>>=) :: Monad m => M a -> (a -> M b) -> M b
pure is sometimes called return and >>= is sometimes called bind and flat map.

I was unsure that bind was the same as flatmap but it looks like it is.

Post reply on HN