I just had a senior engineer on my team ask me whether it was really the case that putting a qualified name or a field access into the beginning of a record update would fail to compile. His examples were much like the other examples from this thread, but I'm noting this here to make clear that this seems to be a routine stumbling block.
Mark > On Mar 9, 2017, at 3:09 PM, Mark Hamburg <[email protected]> wrote: > > 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: >>> >>> 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.
