Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You could make the C# code shorter by using the one-liner record syntax. That would compare the SLOC more fairly.


Here’s version with modern C#:

  public record Product(string Name, decimal Price);
  public record OrderLine(Product Product, int Quantity);

  public abstract record Discount 
  {
      public record Percentage(decimal Value) : Discount();
      public record FixedAmount(decimal Value) : Discount();
  }

  public record Order(List<OrderLine> OrderLines, Discount? Discount)
  {
      public decimal CalculateTotalPrice()
      {
          var subtotal = OrderLines.Sum(x => x.Product.Price * x.Quantity);
          return subtotal - Discount switch
          {
              Discount.Percentage { } percentage => subtotal * percentage.Value / 100M,
              Discount.FixedAmount { } amount => amount.Value,
              _ => 0M
          };
      }
  }


To be fair, you'd still need a private constructor in Discount, otherwise the sumtype is not closed, like it is in the F# case. And the percentage Value should be `float` :)


You also want the subclasses to be `sealed`.

Ideally you would want to write `abstract sealed` for `Discount` too, but C# does not allow it. CIL does support it however, and it is how F# implements sum types. There's no reason I see for C# to continue enforcing this restriction, and lifting it would allow us to write proper DUs.


While I tend to make the SUM type cases sealed, it is theoretically not required to make the sum type closed. All subtypes of a case belong by definition to that case. So any code that handles the defined cases also handles the subclasses implicitly.


I noted the same thing: the C# was unusually verbose.

I thought about switching to F# a few months back, but as I started working with it, it wasn't enough of a benefit over C#.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: