5 ms·
Why do you struggle with this in C#, especially given that you are familiar with the F# style? I don't know C#, but in Java I'd write this as: public class
by mavelikara 8y ago
Why do you struggle with this in C#, especially given that you are familiar with the F# style? I don't know C#, but in Java I'd write this as:
public class Order {
final Optional<DeliveryDetails> delivery;
public Order(Optional<DeliveryDetails> delivery) {
this.delivery = delivery;
}
}
public class DeliveryDetails {
final long deliveryTimeMs;
...
public DeliveryDetails (long deliveryTimeMs,...) {
this.deliveryTimeMs = deliveryTimeMs;
...
}
}
My IDE writes most of these lines for me. I believe C# will have similar or more succinct constrcuts.
- ambulancechaser 8y agothat's true, you can recreate it in some sense but you can't get to what F# can guarantee. A big promise of discriminated unions is the ability to make invalid state unrepresentable. Matching on the different type constructors is a fantastic way to only express coherent states.
- uryga 8y ago> Matching on the different type constructors Terminology nitpick: Pattern matching is done on value constructors (or just "constructors", but at the intersection of FP and OOP that could be confusing). "type constructor" means something like `List` (as opposed to `List[Int]`) – a generic type that hasn't been applied to any type argument(s) yet, and will "construct" a type (like `List[int]`) when you apply it.
- tigershark 8y agoThe ide maybe will write a small part of it, but you’ll have to keep reading it forever. And obviously it is modelled wrong because it is possible to have a Delivered order without delivery details, there is nothing that enforces it. Compare it with how I would write it in f#: type OrderId = OrderId of string type DeliveryTime = DeliveryTime of long type DeliveryDetails = { deliveryTime: DeliveryTime...} type Order = { id: OrderId ...} type DeliveredOrder = { id: OrderId, deliveryDetails: DeliveryDetails...} Probably it is even better to define delivery time using the unit of measures and specifying it as ms. What is the difference in this way? That an order cannot ever have DeliveryDetails, while a DeliveredOrder must have DeliveryDetails. As a bonus you can’t just pass any string as an order id (for example a description) but you need to pass an actual order id. the same is true for the deliveryTime with the adddd advantage that you won’t be able to perform operations on it with a different unit of measure. In java or c# you would kill yourself if you try to do something similar and moreover you won’t have all the constraints specified here and the immutability automatically enforced.
- Dolores12 8y agovery elegant solution. i agree it will take much more time to implement that in c#.
- mavelikara 8y ago> i agree it will take much more time to implement that in c#. If I am reading the code correctly, here is the Java version (with Lombok [1]): @Data class OrderId { final String id; } @Data class DeliveryTime { final long time; } @Data class DeliveryDetails { final DeliveryTime deliveryTime; } @Data class Order { final OrderId id; } @Data class DeliveredOrder { final OrderId id; final DeliveryDetails deliveryDetails; } I can imagine C# also having similar expressive powers. [1] http://jnb.ociweb.com/jnb/jnbJan2010.html http://jnb.ociweb.com/jnb/jnbJan2010.html. Lombok reduces the drudgery of writing some of the code in Java. Modern JVM languages like Scala and Kotlin have native constructs to express this.
- tigershark 8y agoIf you are not writing java and you are using lombok then yes, this simple case seems covered well. I still can’t see how Lombok will help with the exhaustive pattern matching in case the order is a union type of several orders types as explained in my other comment or with avoiding mixing up ms and seconds when using a unit of measure in f# for deliveryTime. Also I’m curious how you would change just one field of an immutable object with 10s of properties in Lombok and if the resulting java code is as efficient as F# with its immutable data structures that use the copy on write semantics.
- mavelikara 8y agoI agree that exhaustiveness check enforced by compiler is something I will miss in Java. Persistent data structures have been implemented in Java if that's what you mean by efficient mutations to immutable structures. I can't imagine such structures being hard in any language hosted on the JVM or CLR. F#, and ML-family languages, surely have their killer features. I am only contesting the claim that the GP made that modeling a domain is a struggle in C# when compared to F#. Imagine if someone came on this thread and claimed that they struggle to write effectful code in F# which they have been writing in Haskell. Of course, you have counter-evidence of that in all the F# programs you have written so far! I feel the same about the inability-to-domain-modeling claim.