Discobooleans and other False Tales of True Type Safety


  • Discourse touched me in a no-no place

    @boomzilla said:

    I think it was originally, but that got switched, IIRC, when someone accidentally posted something with an email address or the like. Probably, @PJH could confirm.

    It got changed around the time the edit windows got shortened:

    [postgres@sofa ~]$ psql -d discourse -c "select uh.updated_at, subject, username, previous_value, new_value
    > from user_histories uh
    > join  users u on u.id=acting_user_id
    > where subject ILIKE '%edit%'
    > order by uh.updated_at asc;"
             updated_at         |            subject             | username | previous_value | new_value 
    ----------------------------+--------------------------------+----------+----------------+-----------
     2014-06-25 15:06:52.932303 | edit_history_visible_to_public | dhromed  | t              | false
     2014-06-25 15:56:02.054118 | ninja_edit_window              | dhromed  | 300            | 60
     2014-06-25 15:56:17.116687 | post_edit_time_limit           | dhromed  | 525600         | 1440
    ...
    


  • I like how we have t and false.



  • @boomzilla said:

    I like how we have t and false.

    Discoboolean



  • I am shamed to admit out legacy product uses the strings "Yes", "Y" and "true" all as truth values : (



  • !Yes == true?



  • We have a method we pass boolean strings to determine if they are actually true or false.

    No "!Yes", just either "No", "N", "False", or "no"



  • We allow 'no', 'off', and 'disabled'. IIRC no 'false' or '0', but I don't recall whether they are case sensitive. They probably are.


  • sockdevs

    @JazzyJosh said:

    We have a method we pass boolean strings to determine if they are actually true or false.

    My quills are twitching like crazy; sounds like a real shit system design
    @PleegWat said:
    We allow 'no', 'off', and 'disabled'.

    Yep, still twitching…
    @PleegWat said:
    IIRC no 'false' or '0'

    :wtf:
    @PleegWat said:
    I don't recall whether they are case sensitive. They probably are.

    Again, :wtf:

    <!-- Emoji'd by MobileEmoji 0.2.0-->



  • sockdevs

    For markup languages, a small set of valid strings is not that bad a way of doing it, as marked-up data is usually meant to be human-readable. But if you're allowing more than a couple of valid T and F values, then you're Doing It Wrong™ ;)

    <!-- Emoji'd by MobileEmoji 0.2.0-->


  • @RaceProUK said:

    My quills are twitching like crazy; sounds like a real shit system design

    Unfortunately this is one of those places where it's best just to contain the bad logic as much as possible instead of crawling through to change stuff.


  • sockdevs

    A wise choice, I'm sure ;)

    <!-- Emoji'd by MobileEmoji 0.2.0-->


  • Go allows you to have multiple named boolean types.



  • That is just what is that? Why would you even do that?



  • With booleans, it's not as useful, but you could do things like define a String method on an integer type and use it to describe flags or making a type that is equivalent to a pointer to an int32 have a Write method that computes some 32-bit hash.

    Basically, any type can be a named type with its own methods.



  • @tar said:

    Why would you even do that?

    Type safety. Paging @antiquarian.

    @ben_lubar said:

    Basically, any type can be a named type with its own methods.

    I would have described it more like a consequence of the equality operator. But then I haven't worked deeply with the sorts of languages that care that deeply about deep types. Deep. Deep. That's fun to type.


  • Discourse touched me in a no-no place

    @boomzilla said:

    But then I haven't worked deeply with the sorts of languages that care that deeply about deep types.

    So you work with the languages with derp types instead? :D



  • It's the equality operator for interface types. Interfaces keep track of the concrete type of their contents as well as the actual contents, so x == y for interfaces checks both the type and the value.

    That means, for example, if you have a type where nil is a valid value and you put nil of that type into an interface variable, x == nil will return false because the nil interface has a nil type as well as a nil value.


  • Discourse touched me in a no-no place

    @boomzilla said:

    Type safety. Paging @antiquarian.

    I got nothing. Segregating floats that represent weight from floats that represent velocity makes sense, but truth is truth (unless we're on the Problem of Evil thread).



  • But toolbarVisible is not the same as sidebarVisible.
    Doesn't it make sense to have type-safe boolean enums?



  • If you're going to have type safe types, it seems less WTFy to not cherry pick which types that applies to, even if it means that @ben_lubar is going to call you out on it.


  • sockdevs

    As far as I'm concerned, type safety is all-or-nothing. Half-assed type safety? TDEMSYR :smile:

    <!-- Emoji'd by MobileEmoji 0.2.0-->

  • Winner of the 2016 Presidential Election

    @boomzilla said:

    I like how we have t and false.

    Postgres is actually very lenient on various input formats for booleans. I never saw it print it out like this though.

    I'm giving Discodevs far too much credit by assuming booleans, am I?



  • @antiquarian said:

    but truth is truth

    But not all two state elements really mean "truth". Consider "On"/"Off" vs. "In/Out" vs. "True/False". All could be represented by enums with two defined states, though the last one should probably use a built in Boolean type. Alas many systems use a Boolean type for all of them!


  • sockdevs

    @TheCPUWizard said:

    Alas many systems use a Boolean type for all of them!

    And why not? If you have something that can only have two states, the most applicable model is a Boolean.

    <!-- Emoji'd by MobileEmoji 0.2.0-->


  • I don't think you should use a boolean type for in/out.


  • sockdevs

    Well… maybe, maybe not. Depends on the application.

    <!-- Emoji'd by MobileEmoji 0.2.0-->


  • @RaceProUK said:

    Well… maybe, maybe not. Depends on the application.

    If the application is "the hokey cokey", you might need to add "shake it all about" as an option at some point.


  • Winner of the 2016 Presidential Election

    @Keith said:

    use a boolean type for in/out.

    Bool ShakeItAllAbout


  • @Jaloopa said:

    Bool ShakeItAllAbout

    So would you define the in/out boolean as nullable?



  • @Keith said:

    So would you define the in/out boolean as nullable?

    Needs to be an enum:

    enum InOrOut
      IN,
      OUT,
      JUST_THE_TIP;
    

  • Winner of the 2016 Presidential Election

    Good question.

    Another potential type that could be represented by a bool is, of course, FILE_FOUND


  • sockdevs

    @boomzilla said:

    ```
    enum InOrOut
    IN,
    OUT,
    JUST_THE_TIP;

    :giggity:
    
    <!-- Emoji'd by MobileEmoji 0.2.0-->

  • Discourse touched me in a no-no place

    @TheCPUWizard said:

    But not all two state elements really mean "truth". Consider "On"/"Off" vs. "In/Out" vs. "True/False". All could be represented by enums with two defined states, though only the last one should probably use a built in Boolean type. Alas many systems use a Boolean type for all of them!

    FTFY

    Boolean should be reserved for True/False. For anything else, make a new enum.

    @RaceProUK said:

    And why not? If you have something that can only have two states, the most applicable model is a Boolean.

    BURN THE HERETIC!

    @boomzilla said:

    Needs to be an enum:

    enum InOrOut
      IN,
      OUT,
      JUST_THE_TIP,
      IS_IT_IN_YET;
    ```</blockquote>

  • Discourse touched me in a no-no place

    @RaceProUK said:

    And why not? If you have something that can only have two states, the most applicable model is a Boolean.

    data CanHaz a = Haz a | ButIEatedIt
    


  • t and f is how PostgreSQL's displays booleans.

    Of course, previous_value (which is a string) was likely fetched from the table, while new_value (also a string) is inserted directly by Discourse.

    Then again, that's just a guess.



  • So is it kinda like overriding Object.equals() in Java? Speaking off complete ignorance here.


  • Winner of the 2016 Presidential Election

    @powerlord said:

    Of course, previous_value (which is a string) was likely fetched from the table, while new_value (also a string) is inserted directly by Discourse.

    I'm still wondering what kind of dickweedery made them use a string in the first place. Maybe someone was worried because they saw true and false in code instead and thought Postgres won't be able to handle it?

    postgres=# create temp table booleans (val boolean);
    CREATE TABLE
    postgres=# insert into booleans(val) VALUES('t');
    INSERT 0 1
    postgres=# insert into booleans(val) VALUES('false');
    INSERT 0 1
    postgres=# insert into booleans(val) VALUES('YES');
    INSERT 0 1
    postgres=# insert into booleans(val) VALUES('n');
    INSERT 0 1
    postgres=# insert into booleans(val) VALUES('1');
    INSERT 0 1
    postgres=# select * from booleans;
     val 
    -----
     t
     f
     t
     f
     t
    (5 rows)
    

    Mistaken, of course...



  • ...you mean other than previous_value and next_value storing numbers in the other two rows returned? Or did you mean in the actual users table?



  • @RaceProUK said:

    If you have something that can only have two states, the most applicable model is a Boolean.
    Sometimes. There are two conditions I think have to be satisfied: (i) there has to be very little chance of adding a third value, and (ii) there has to be an almost unambiguous mapping from "true/false" to your semantic meanings.

    I'll give an example that fails both. I have a function output_thing(Thing thing, Format format) that will print out thing in either plain text or with fancy Unicode characters (welcome to the 90s baby!). For me, Format is an enumeration, but under that description it could be a bool. But what does true mean? ASCII or Unicode? I mean, I could argue it makes a little more sense to mean Unicode because "should I do this fancier thing" seems a more natural question than "should I use the basic version" in this example, but I'm not sure everyone would agree and it may just be because I added Unicode later. So it fails the first criteria. It also fails the second, because I lied above; I added a third output format, HTML. If I had chosen a bool initially, I'd have had to completely change the type; with an enumeration, I just added a third option.

    (I think the in/out example also fails criteria (i). I don't think there's a clear mapping of those to true/false in most cases.)


  • Winner of the 2016 Presidential Election

    @powerlord said:

    ...you mean other than previous_value and next_value storing numbers in the other two rows returned? Or did you mean in the actual users table?

    D'OH! The damned thing confused me so much I thought this is describing the columns themselves, only now have I read the query properly.

    Hey, gimme a break, I saw the JSON this thing produces, I expect idiocy first now. They lost my benefit of a doubt a long time ago.



  • Did this thread get discosorted in the move? Because post #5 is a direct response to post #22 now. :wtf:



  • I like how the "go to the quoted post" links all take you back to the song of the day thread, but to completely random posts.

    EDIT: And the "expand/collapse" button just gives me "Loading...".



  • @tar said:

    That is just what is that? Why would you even do that?

    Sounds sensible in any strongly-typed language. Compiler can stop you if you're mixing bools-- like assigning a user-set option to a hardware-configuration option.


  • sockdevs

    Don't see how that's any better than using enums. Unless, of course, the language doesn't have enums.

    <!-- Emoji'd by MobileEmoji 0.2.0-->


  • @boomzilla said:

    If you're going to have type safe types, it seems less WTFy to not cherry pick which types that applies to, even if it means that @ben_lubar is going to call you out on it.

    Yes. I've made this bitch about C# before, as you might recall. People seem to have trouble with the concept of "strongly typed" and assume that the way C/C++ does it is the best way. But the thing is: C/C++ have a ton of weird cases where they do conversions for you (like char -> byte), and that's exactly the opposite of what you want in a strongly-typed language.



  • @RaceProUK said:

    Don't see how that's any better than using enums.

    Maybe it's not, but I also don't see any reason it should be disallowed.



  • @blakeyrat said:

    Sounds sensible in any strongly-typed language. Compiler can stop you if you're mixing bools-- like assigning a user-set option to a hardware-configuration option.

    I suppose. But making a boolean value called maybe which is neither equal to true nor false? It should be called file_not_found!



  • @tar said:

    Did this thread get discosorted in the move? Because post <a href="/t/abc/8647/5">#5</a> is a direct response to post <a href="/t/abc/8647/22">#22</a> now. :wtf:

    I believe #22 was the one I missed on my initial Jeffing.



  • It's more like if Object.equals simply compared the types and fields and was final.


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.