I got asked for non obfuscated/simplified examples, so let me run through
some more realistic code. I would pull from our own codebase but we've
often contorted ourselves away from these patterns because they are so ugly
so I can't just grab existing code.

Imagine having a style element that includes information about padding on
each side:

type Rect = { left : Int, top : Int, right : Int, bottom : Int }

type Style = { padding : Rect, ... }


Expressing it this way allows us to work with the padding as a whole when
useful and to avoid having to work with field names like leftPadding,
topPadding, etc (presumably along with leftMargin, topMargin, etc)

But now say one wants to change just the left padding. The code has to
build a new padding object and then stick it back into the style. A little
ugly from the standpoint of repetition, but maybe just...

{ style | padding = { style.padding | left = 10 } }


Nope. We can't use an expression for the record to be updated. So, instead
we have to write something more like:

let
    oldPadding =
        style.padding
    newPadding =
        { oldPadding | left = 10 }
in
    { style | padding = newPadding }


Or we can use the successive wrapping pattern if we have the necessary
utility functions:

10 |> asLeftIn style.padding |> asPaddingIn style


And the inability to use an expression to derive the record also means that
we can't do something like:

{ Style.default | color = "red" }

But rather have to write:


defaultStyle : Style.Style
defaultStyle = Style.default

...

{ defaultStyle | color = "red" }

I don't have a good answer to the ugliness of the nested update though the
successive wrapping pattern would probably be pretty reasonable if we had
.field= in addition to .field. But the latter problem seems like the sort
of thing that should be very straightforward to solve and would also allow
for writing the first version of updating the left padding that I wrote
above.

Mark

On Fri, Mar 3, 2017 at 8:44 AM, Mark Hamburg <[email protected]> wrote:

> Our codebase suffers from this as well. And unlike what one of the follow
> ups noted, this isn't an issue of wanting to add fields. Rather, it's an
> issue of not being able to use an expression in the first part of the
> record update. In this case, one doesn't even need a general expression but
> just an imported value. On the  their hand, members of my team have gotten
> bit by and complained about not being able to construct a nested update
> using what they thought were the language constructs:
>
>     newFoo = { oldFoo | nested = { oldFoo.nested | field = 3 } }
>
> The "best" syntax I've seen for that is something like:
>
>     newFoo =
>          3 |> asFieldIn oldFoo.nested |> asNestedIn oldFoo
>
> But that's pretty obscure as well.
>
> That said, I just added a utility module to our project that is filled
> with generic setFoo and asFooIn functions for every field name that seems
> at all likely to be used more than once. I would love to have support for
> .field= functions to parallel the .field functions. I would have them take
> the assigned value as a first parameter and the record as a second
> parameter to enable writing:
>
>     Slides.defaultConfig
>         |> .someAttribute= myCustomValue
>
> The case where the parameters are reversed which helps with nesting could
> be handled using a utility function:
>
>      3
>         |> into oldFoo.nested .field=
>         |> into oldFoo .nested=
>
> Mark
>
> On Mar 2, 2017, at 10:16 PM, Richard Feldman <[email protected]>
> wrote:
>
> Re-posting the first example from Franscisco's thread
> <https://groups.google.com/forum/#!topic/elm-discuss/vzcrRdgY1-w>:
>
> There is a common pattern where a library (ex, elm-markdown) will provide
> a default config, to be extended by the user.
>
> Here the two ways to do this right now, one painfully verbose and the
> other relying on exposing values that would read better if fully qualified
> instead of exposed:
>
> import Slides
>
> slidesDefaultConfig =
>   Slides.defaultConfig
>
> myCustomSlidesConfig =
>  { slidesDefaultConfig | someAttribute = myCustomvalue }
>
> or
>
> import Slides exposing (slidesDefaultConfig)
>
> myCustomSlidesConfig =
>  { slidesDefaultConfig | someAttribute = myCustomvalue }
>
> Not a big deal TBH, but annoying.
>
>
> --
> 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.
>
>

-- 
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