Yes you're right, I hadn't seen it that way, thanks.

On Tuesday, August 23, 2016 at 11:48:43 AM UTC+2, Janis Voigtländer wrote:
>
> Well, actually it would have been (swapped argument order compared to what 
> I wrote before):
>
> init : a -> Model ainit old = Model 4 old
>
> But the point stands, that you would only need the row "record 
> constructors that add fields" from 
> https://github.com/elm-lang/elm-platform/blob/master/upgrade-docs/0.16.md#updating-syntax
>  
> to be reverted.
>
>
> 2016-08-23 11:27 GMT+02:00 Janis Voigtländer <[email protected] 
> <javascript:>>:
>
>> You should be able to do that.
>>
>> If you have
>>
>> type alias Model a =
>>    { a | newField : Int }
>>
>> then
>>
>> init : a -> Model ainit old = Model old 4
>>
>> is exactly equivalent (in pre-0.16 Elm) to
>>
>> init : a -> Model ainit old = { old | newField = 4 }
>>
>> So where’s the problem? 
>> ​
>>
>> 2016-08-23 11:10 GMT+02:00 Charles-Edouard Cady <[email protected] 
>> <javascript:>>:
>>
>>> I'm not sure: I don't think I'll be able to define an init function 
>>> like the following if I don't also have the "field addition" changes 
>>> reverted:
>>>
>>> init : a -> Model a
>>> init old =
>>>   { old | newField = 4 }
>>>
>>>
>>>
>>> On Tuesday, August 23, 2016 at 10:29:59 AM UTC+2, Janis Voigtländer 
>>> wrote:
>>>>
>>>> Is it correct that your issue could be addressed by not bringing back 
>>>> arbitrary record extension in expressions via the pre-0.16 syntax { 
>>>> ... | ... = ... }, but *only* bringing back constructor functions for 
>>>> extensible records? That is, if from the table at 
>>>> https://github.com/elm-lang/elm-platform/blob/master/upgrade-docs/0.16.md#updating-syntax
>>>>  
>>>> only language change in the row “record constructors that add fields” were 
>>>> reverted, but not the language changes in the other rows?
>>>>
>>>> Also relevant in this context, then: 
>>>> https://github.com/elm-lang/elm-compiler/issues/1308.
>>>>
>>>> 2016-08-23 10:23 GMT+02:00 Charles-Edouard Cady <[email protected]
>>>> >:
>>>>
>>>>> Greetings!
>>>>>
>>>>> I originally posted this on 
>>>>> https://github.com/elm-lang/elm-compiler/issues/985 which, as Richard 
>>>>> Feldman pointed out, is probably not the best place to put it. I'll 
>>>>> follow 
>>>>> Richard's suggestion & be a bit less abstract.
>>>>>
>>>>> I'm building an application to help ship captains create routes. My 
>>>>> question is about the organization of the model of this application.
>>>>>
>>>>> The application currently has one page containing three widgets:
>>>>>
>>>>>    1. A map showing the routes
>>>>>    2. A table showing the performances (eg. fuel consumption, 
>>>>>    duration...) of each route
>>>>>    3. A profile widget showing the speed profile on the selected route
>>>>>
>>>>>
>>>>> It is structured in three layers of decreasing size (and increasing 
>>>>> versatility):
>>>>>
>>>>>
>>>>>    1. The top layer, providing synchronization between the widgets 
>>>>>    and the layout of the page
>>>>>    2. The widget layer (all widgets are independent)
>>>>>    3. The elementary widget layer (containing sliders, date 
>>>>>    pickers...) ie. reusable components
>>>>>
>>>>>
>>>>> The reusable components have their own model, which is independent 
>>>>> from the rest of the application: their model is initialized by their 
>>>>> containing widget.
>>>>> The widgets, however, must share some information (eg. the list of 
>>>>> routes) but not all (for example, the profile widget couldn't care less 
>>>>> which route is hovered in the table widget, but the map widget does) 
>>>>> because it complicates refactoring (changing the model one widget impacts 
>>>>> the others) and makes it difficult to reuse widgets (eg. use the profile 
>>>>> widget in a context where I do not need/have the fuel consumption).
>>>>>
>>>>> Now in Elm's architecture tutorial, there are two extreme cases:
>>>>>
>>>>>    - The same model is shared by all widgets
>>>>>    - Each widget has its own independent model
>>>>>
>>>>>
>>>>> I find myself somewhere in between: part of the model is shared by all 
>>>>> widgets and is application-independent (eg. the waypoints of each route), 
>>>>> part of it is shared only by two widgets and mostly concerns the layout 
>>>>> (eg. route hovering) and part of it is not shared (and should not be) 
>>>>> (eg. 
>>>>> the sliders' state).
>>>>>
>>>>> At the top-level (Page):
>>>>>
>>>>>
>>>>> type alias Model a =
>>>>>   { a
>>>>>   | routes : List Route
>>>>>   , hovered : Maybe Int
>>>>>   , selected : Maybe Int
>>>>>   , map : Map.InternalModel
>>>>>   , table : Table.InternalModel
>>>>>   , profile : Profile.InternalModel
>>>>>   }
>>>>>
>>>>> The Profile widget might use a part of this model:
>>>>>
>>>>> type alias Model a =
>>>>>   { a
>>>>>   | route : List Route
>>>>>   , selected : Maybe Int
>>>>>   , profile : InternalModel
>>>>>   }
>>>>>
>>>>> while the Table widget uses another:
>>>>>
>>>>> type alias Model a =
>>>>>   { a
>>>>>   | route : List Route
>>>>>   , selected : Maybe Int
>>>>>   , hovered : Maybe Int
>>>>>   , table : InternalModel
>>>>>   }
>>>>>
>>>>>
>>>>> Just like @rgrempel in 
>>>>> https://github.com/elm-lang/elm-compiler/issues/985, I want each 
>>>>> module also provides its init function to initialize its part of Page's 
>>>>> model. With extensible records, I could simply do (eg. in Table):
>>>>>
>>>>> init : a -> Model a
>>>>> init foo =
>>>>>   {foo | table = initInternal}
>>>>>
>>>>> and for Page I would have the very clean and composible chain:
>>>>>
>>>>> init : Model
>>>>> init =
>>>>>   {routes = []}
>>>>>   |> Table.init
>>>>>   |> Profile.init
>>>>>
>>>>> So the extensible records were an easy way for me to build composable 
>>>>> applications. With the removal of this feature, the init function can 
>>>>> no longer be type-parametrized. This is really important so let me 
>>>>> emphasize a bit: *no extensible records means init must know the full 
>>>>> record it operates on*.
>>>>>
>>>>> So I decided to use @rgrempel's strategy, but in his case where all 
>>>>> parts of his model were independent. The only workaround I found is to do 
>>>>> the following for Page (top-level):
>>>>>
>>>>> type alias Model a =
>>>>>   { a
>>>>>   | shared : Shared.Shared
>>>>>   , map : Map.InternalModel
>>>>>   , table : Table.InternalModel
>>>>>   , profile : Profile.InternalModel
>>>>>   }
>>>>>
>>>>> init : Model
>>>>> init =
>>>>>   { shared = Shared.init
>>>>>   , map = Map.init
>>>>>   , table = Table.init
>>>>>   , profile = Profile.init
>>>>>   }
>>>>>
>>>>> When you loose extensible records you have to put all shared parts in 
>>>>> a Shared record, which essentially means you know in advance how your 
>>>>> widget will be used.  For instance, the data shared by the Profile 
>>>>> and the Table widgets is not the same as that used by the Profile and 
>>>>> the Map widgets and if I add another widget, chances are I'll have to 
>>>>> modify the Shared record. This makes me sad because it breaks 
>>>>> separation of concern. With extensible records, I could simply add the 
>>>>> fields I need to Page's model & in the specific widgets & they would 
>>>>> simply be ignored by the other widgets. Whenever I modify what is shared, 
>>>>> I'm modifying the Shared record that all widgets depend on &o if I 
>>>>> decide to use eg. the Profile widget in another application, it will 
>>>>> quickly become unmanageable.
>>>>>
>>>>> As previously stated, as soon as you define an init function, the 
>>>>> record it returns (or operates on) can no longer be type-parametrized 
>>>>> (i.e. 
>>>>> extensible), which means that if init returns the shared part, Shared 
>>>>> is no longer extensible. If Shared is not extensible & you want to 
>>>>> include Page in a bigger application, Page's model will have to be 
>>>>> completely independent from the other widgets' model at the same level, 
>>>>> ie. 
>>>>> it will not be able to share part of its model with the other widgets.
>>>>>
>>>>> With extensible records, you could apply the same pattern to any 
>>>>> number of levels, but as soon as you put shared data in a shared 
>>>>> field you're basically stating once and for all what is shared by all 
>>>>> possible widgets: that information is only needed at the application 
>>>>> level 
>>>>> (at the Page level), but it dribbles down to all widgets (which 
>>>>> shouldn't care whether they're being used in isolation or not).
>>>>>
>>>>> Sorry to ramble on about this, but it's been a thorn in my side for a 
>>>>> long time now.
>>>>>
>>>>> I would really appreciate any thoughts on this.
>>>>>
>>>>> -- 
>>>>> 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] <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