← Back to context

Comment by pmontra

3 days ago

Probably Elixir spoiled me but when I see

  enum Shape {
    case Circle(Int32),
    case Square(Int32),
    case Rectangle(Int32, Int32)
  }
  def area(s: Shape): Int32 = match s {
    case Circle(r)       => 3 * (r * r)
    case Square(w)       => w * w
    case Rectangle(h, w) => h * w
  }

I wonder why not this syntax:

  def area(s: Shape.Circle(r)) = { 3 * (r * r) }
  def area(s: Share.Square(w)) = { w * w }
  def area(s: Shape.Rectangle(h, w)) = { h * w }

  area(Shape.Rectangle(2, 4))

The Int32 or Int32, Int32 types are in the definition of Shape, so we can be DRY and spare us the chances to mismatch the types. We can also do without match/case, reuse the syntax of function definition and enumerate the matches in there. I think that it's called structural pattern matching.

> The Int32 or Int32, Int32 types are in the definition of Shape, so we can be DRY and spare us the chances to mismatch the types

I have to admit I don't see the distinction here in terms of DRYness--they are basically equivalent--or why the latter would somehow lead to mismatching the types--presumably if Flix has a typechecker this would be a non-issue.

I use Elixir now at work and I have used Haskell and PureScript personally and professionally, which both support analogs of both the case syntax and function-level pattern matching, and in my experience the case syntax is often the better choice even given the option to pattern match at the function level. Not that I'd complain about having both options in Flix, which would still be cool, but I don't think it's as big of a benefit as it may seem, especially when type checking is involved.

  • Because I might write

      enum Shape {
        case Circle(Int32),
    
      def area(s: Shape): In32 = match s {
    

    Not only I had to write something that the compiler already knows, but I typed a compilation error. The second type definition is there only to make developers write it wrong. It does not add any information.

    • > The second type definition is there only to make developers write it wrong.

      Int32 is the type of the return value for the function (https://doc.flix.dev/functions.html), which is distinct information not implied by the type being passed in (Shape), so I dispute this characterization--the fact that this type is the same type as the parameter given to all of Shape's terms is specific to this example. Furthermore I suspect it would immediately be caught by the typechecker regardless.

      While in a language like Haskell you could define this function without a type definition and its type would be inferred (vs. in Flix, see https://doc.flix.dev/functions.html?highlight=inference#func...), regardless I will almost always declare the type of top-level functions (or even non-top-level functions) for clarity when reading the code. I think this is useful and important information in any case.

      1 reply →

    • What if you make a typo and instead of `area` you type `areas` the second time? I also don't see how one is more DRY than the other. If anything in the second example you typed `Shape` and `area` a bunch of times, so to me it's less DRY

> can also do without match/case, reuse the syntax of function definition and enumerate the matches in there. I

I think that is multi-methods