You might also consider adding a factory member to your DU type:

1
2
3
4
5
type SomeMessage =
    | CustomerCreated of Guid * string * string * string
    with 
    static member Create(guid, customerName, contactName, email) =
        CustomerCreated(guid, customerName, contactName, email)

Users of your factory function will get strong Intellisense in both F# and other .NET languages.

By on 3/29/2010 4:32 AM ()

In F# and elsewhere I usually take the approach of using lighter weight but less self-documenting types in narrower contexts where their meaning is obvious. As the context broadens, even out to .NET interoperability, heavier weight constructs become more appropriate.

In local contexts, say a page or two of code where all the types are available at a glance, heavy-weight constructs can actually clutter the code. In library contexts, however, self-documenting types are essential.

Tuples I use in cases where either the use of the tuple as a type is an obvious solution or two return and pass multiple values. The C++ STL, I think, demonstrates the appropriate use of tuples in its pair<'a,'b> class.

-Neil

By on 3/29/2010 8:05 AM ()

Perhaps it’s a too naïf to cover all the cases, but I think a good rule of thumb is that it’s okay to use tuples with a module, but if the tuple escapes the module then you should change it to a record.

One notable exception is where tuples have a “natural order”, i.e. Point(int * int), here it’s obvious that the first item in the tuple is x and the second is y.

Cheers,

Rob

By on 3/29/2010 8:46 AM ()

I would use a record as the DU case here :

1
2
3
4
5
type SomeMessage =
    | CustomerCreated of CustomerCreatedInfo
    | ...
and CustomerCreatedInfo = { Guid : Guid; Name : string; Contact: string; Email : string }

I tend to prefer records over tuples when there are too many components and the types themselves
don't convey enough information.

By on 3/29/2010 2:48 AM ()

I would use a record as the DU case here :

1
2
3
4
5
type SomeMessage =
    | CustomerCreated of CustomerCreatedInfo
    | ...
and CustomerCreatedInfo = { Guid : Guid; Name : string; Contact: string; Email : string }

I tend to prefer records over tuples when there are too many components and the types themselves
don't convey enough information.

Thanks, so far this seems like the best approach.

I'm evaluating if F# would fit my needs for a message based system (fit better than c# that is, playing around with eventsourced CQRS in F#)

The problem I see with DU's and records:

DU: not self descriptive in global context.

Records: can be ambigous definition.

eg:

//naive messages just to show my point

type CustomerDeleted = { Id: Guid }

type OrderDeleted = { Id: Guid }

There is no way (afaik) to distinguish the two since they are identified by structure.

let foo = { Id = ... }

bubobubo approach seems to solve both problems.

By on 3/29/2010 9:29 AM ()

let foo = {CustomerDeleted.Id = ... }

let bar = {OrderDeleted.Id = ...}

It is enough to supply type only for first field even if records structurally equals and have many fields.

By on 3/30/2010 4:09 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper