← Back to context

Comment by jzebedee

21 hours ago

C# is strongly-typed, not stringly-typed. The point of the union is to list possible outcomes as defined through their respective types.

The idiomatic way to do this would be to parse, don't validate [1] each string into a relevant type with a record or record struct. If you just wanted to return two results of the same type, you'd wrap them in a named tuple or a record that represented the actual meaning.

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

I guess C# is more strongly-typed than Haskell then... /s

  • String literal typing appears to be a common feature of type systems bolted onto dynamic languages:

        # Python
        MyStringBool = Literal("Yes") | Literal("No")
    
        // TypeScript
        type MyStringBool = "Yes" | "No"
    

    I assume it exists to compensate for the previous lack of typing, and consequent likelihood of ersatz typing via strings.

    It would seem pretty unnecessary in Haskell, where you can just define whatever types you want without involving strings at all:

        data MyBool = Yes | No
    

    Of course you'd need a trivial parser, though this is probably a good idea for any string type:

        parseMyBool :: String -> MyBool 
        parseMyBool "Yes" = Yes
        parseMyBool "No" = No
        parseMyBool _ = error "..."
    

    Interestingly, dynamic languages which make use of symbols (Ruby, Elixir, Common Lisp) probably fall closer to Haskell than Python or TS. Elixir example:

        @type my_bool() :: :yes | :no
    
        @spec parse_my_bool(String.t()) :: my_bool()
        def parse_my_bool("Yes"), do: :yes
        def parse_my_bool("No"), do: :no
        def parse_my_bool(_), do: throw("...")
    

    Where :yes and :no are memory-efficient symbols, not strings.

    • String literals are structural types which are way more expressive than regular (Haskell) ADTs, which are nominal types.

      In TS in particular, in combination with other features (mapped types), they are equivalent to row polymorphism + whatever Haskell/GHC features enable type families to specialize on constant literal arguments (or you can use atomic types, but that's not structural / open-world)... so pretty advanced.

      This is valid TS/Python:

          type ABC = "A" |"B" | "C"
          type AB = "A" | "B"
          const x: AB = "A";
          const y: ABC = x;
      

      The equivalent Haskell requires using several extensions.

      8 replies →