Fable: Attribute to compile arguments as JS object

Created on 30 Oct 2018  ·  3Comments  ·  Source: fable-compiler/Fable

The new additions to React (memo, hooks) indicates the community is going to move more towards functions as components rather than classes. This is good news for us, because the class syntax in F# is a bit verbose for this purpose. However, there are still things we can do to improve the experience.

At FableConf @vbfox suggested to enable an attribute to compile arguments as a JS object, so we don't need to declare a record every time we want to define a function component with props. So instead of:

type MyProps = { key: string; value1: int; value2: float[] }

let MyComponent (props: MyProps) =
    div [] [...]

// Use
ofFunction MyComponent { key = "foo"; value1 = 5; value2 = [] } []

We could write:

let [<MagicAttribute>] MyComponent (key: string) (value1: int) (value2: float[]) () =
    div [] [...]

// Use?
ofFunction2 (MyComponent "foo" 5 []) []

I just noticed we forgot to discuss how this would be called. In the sample above I just added a unit argument at the end to prevent execution, but there may be other ways.

In principle, I wanted to avoid magic attributes in F# as much as possible, but it could be justified in this case. An alternative could be to just wait until anonymous records come into F#. They may solve this situation and we would align to standard F#, and it seems they will be early in F# previews.

discussion

Most helpful comment

Anonymous records are still pretty verbose :

// Declaration
let userView = namedMemo "User" (fun ({| UserId: string; Name: string |}) ->
    a [Href (sprintf "/%s/" props.UserId)] [str props.Name])

// Usage
ofElementType userView { UserId = "vbfox"; Name = "Julien Roncaglia" } []

Normal records :

// Declaration
type UserViewProps = { UserId: string; Name: string }
let userView = namedMemo "User" (fun props ->
    a [Href (sprintf "/%s/" props.UserId)] [str props.Name])

// Usage
ofElementType userView { UserId = "vbfox"; Name = "Julien Roncaglia" } []

But the more I think about my proposal the more I see problems with it... Even with such a primitive it would allow for functional components to work but not wrapped ones like memo as the argument names would be lost from the compiler :( :( :(

I think you can close this @alfonsogarciacaro I'll reopen one if I find a way to solve this... For now we'll create records or tuples XD

All 3 comments

An alternative could be to just wait until anonymous records come into F#

Since the issue is already addressed on the F# part of things and there is already an alternative in Fable by defining a record, I would suggest to wait until we have anonymous records. Otherwise you will only add a feature that will be removed in the near future, not to mention that it must be implemented, tested, documented , added with some examples and users will need to learn yet another attribute next to their arsenal of Fable quirks that do javascripty things

I am in favor for waiting anonymous F# record

Anonymous records are still pretty verbose :

// Declaration
let userView = namedMemo "User" (fun ({| UserId: string; Name: string |}) ->
    a [Href (sprintf "/%s/" props.UserId)] [str props.Name])

// Usage
ofElementType userView { UserId = "vbfox"; Name = "Julien Roncaglia" } []

Normal records :

// Declaration
type UserViewProps = { UserId: string; Name: string }
let userView = namedMemo "User" (fun props ->
    a [Href (sprintf "/%s/" props.UserId)] [str props.Name])

// Usage
ofElementType userView { UserId = "vbfox"; Name = "Julien Roncaglia" } []

But the more I think about my proposal the more I see problems with it... Even with such a primitive it would allow for functional components to work but not wrapped ones like memo as the argument names would be lost from the compiler :( :( :(

I think you can close this @alfonsogarciacaro I'll reopen one if I find a way to solve this... For now we'll create records or tuples XD

Was this page helpful?
0 / 5 - 0 ratings

Related issues

et1975 picture et1975  ·  3Comments

jwosty picture jwosty  ·  3Comments

krauthaufen picture krauthaufen  ·  3Comments

nozzlegear picture nozzlegear  ·  3Comments

MangelMaxime picture MangelMaxime  ·  3Comments