This was touched on in a related way in this thread:

https://groups.google.com/d/msg/elm-discuss/0XbEEb4hkjM/dy6Q3XHIBgAJ

and is also related to some of the recent discussion of aliases to aliases,
but neither of those touch quite as directly on this issue/request.

In reviewing the Elm code my team has been writing, I see a lot of tension
around whether one should construct record-based models in submodules as:

type alias Model = { x : Int, y : Int }

Or as:

type Model = Imp { x : Int, y : Int }

where Imp is private. Or even as:

type alias Imp = { x : Int, y : Int }
type Model = I Imp


The first form results in the most straightforward code because it avoids
wrapping an unwrapping, however, it exposes the model to manipulation by
any importing modules. The second form doesn't make the type declaration
that much more complex but it means that all uses need to wrap and unwrap
and it becomes harder to use the record access and update syntax to create
useful composable functions. The last form results in the easiest
construction for structuring the code internally because all of the
internal functions can use Imp while the exported functions use Model. This
last construction, however, starts to feel more convoluted.

Furthermore, the wrapping and unwrapping gets messier if I want to avoid
creating new model objects when the model doesn't change — good to do if
using lazy HTML generation. In this case, it is safe to compare two imps
and just use the original model if the new imp equals the old, but this
won't work if the actual type includes a function since those aren't
comparable for equality. This is part of why I shifted first internal
functions and eventually the exported update function to use Maybe in the
results so that a Nothing result could signal no change, but that's a more
complicated style to get used to as well.

Now, one could argue that the first form is just fine as long as one isn't
writing a package and on a sufficiently small, sufficiently disciplined
team it would be. I've written a lot of Lua code with other developers and
everyone grokked the notion that fields with names starting with an
underscore were private. But Elm emphasizes replacing convention with
linguistic enforcement and while this might matter more at a package
boundary level, what's good at those boundaries is likely also good between
modules in general.

So, now we come to the suggestion. What if Elm allowed one to write:

type Model = { x : Int, y : Int }

This is syntactically compatible with existing Elm code (since it's
disallowed in existing Elm code). It's meaning would be similar to the
second form above but the tag could not be exported since it is hidden in
even the defining model, the wrapping and unwrapping would be automatic,
and Model would be eligible within the defining module for use with the
record access and update syntax. In other words, it would operate just like
the first form within the module but just like the second form outside the
module.

At least within the code my team has written, I could see this becoming the
standard way to build record types with the type alias syntax only being
used when it was useful to export the record definition itself. It also
makes it easier to explain to new programmers how to use records because
one can start by training people to use type for all declarations and only
get around to explaining type alias later. ("Let's Be Mainstream!")

Mark

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to