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 <janis.voi...@gmail.com 
> <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 <charlesed...@gmail.com 
>> <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 <charlesed...@gmail.com
>>>> >:
>>>>
>>>>> 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 elm-discuss...@googlegroups.com.
>>>>> 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 elm-discuss...@googlegroups.com <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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to