It's not a huge deal but other strongly typed languages definitely allow 
arbitrary expressions in record update syntax.

# type t = { a : int ; b : float } ;;

type t = { a : int; b : float; }

# let emptyT () = { a = 1 ; b = 3.0 } ;;

val emptyT : unit -> t = <fun>

# let x = { (emptyT ()) with a = 7 } ;;

val x : t = {a = 7; b = 3.}

On Saturday, March 18, 2017 at 10:26:57 AM UTC-7, Mark Hamburg wrote:
>
> 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] <javascript:>> 
> 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] 
> <javascript:>> 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] 
>> <javascript:>> 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] <javascript:>.
>> 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