Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access arguments? #11

Open
dead-claudia opened this issue Oct 29, 2017 · 15 comments
Open

Access arguments? #11

dead-claudia opened this issue Oct 29, 2017 · 15 comments

Comments

@dead-claudia
Copy link

In many DSLs, it's convenient to have the ability to pass arguments to the callback as well - a good example of this is with arguments for a makefile task, but also, most of the binding-related stuff could be addressed similarly by simply accepting arguments.

My first instinct would be something like this (obvious Ruby inspiration):

forEach(items) do (item) {
    // ...
}
@samuelgoto
Copy link
Owner

Yep, indeed. I left this as an extension here:

https://github.com/samuelgoto/proposal-block-params#bindings

WDYT?

@dead-claudia
Copy link
Author

Eh...it makes sense in some contexts (like iteration), but not in others (makefile task arguments).

I did read that after I filed this, but that idea really didn't feel right, especially if you have more than one parameter passed to the block (consider task name + dependencies).

@samuelgoto
Copy link
Owner

Yep, agreed that the syntax needs more work. Can you help me identify what are the most common use cases where you'd want arguments?

especially if you have more than one parameter passed to the block (consider task name + dependencies).

fwiw, in the current formulation,multiple parameters could be set:

foreach ({key, value} in map) {
  // ...
}

@dead-claudia
Copy link
Author

The most common use cases would be in iteration-like contexts, but not all iteration is synchronous (like above). One example where multiple distinct arguments would be nice would be with native forEach, which would work out-of-the-box with explicit parameters:

list.forEach do (item, i) {
    // Do something that requires both the current item and its index.
}

fwiw, in the current formulation,multiple parameters could be set:

To clarify, I'm speaking about the callee's side, not the callback's side:

task("foo", ["dep1", "dep2"]) do (args) {
    // ...
}

While looking at porting some of my own code (a WIP DOM framework) over to use this, I ran into one case, although your binding proposal would work:

// Original
r.dynamic(stream, (r, item) => {
    // re-render on each received item
})

// This proposal
dynamic(stream) do (item) {
    // re-render on each received item
}

// Binding proposal
dynamic(item in stream) {
    // ...
}

Also, previously, I had my components defined like this:

// Original
const Component = m.component((r, attrs, children) => {
    // ...
})

// What it could be
const Component = m.component do (attrs, children) {
    // ...
}

@samuelgoto
Copy link
Owner

samuelgoto commented Oct 30, 2017

The most common use cases would be in iteration-like contexts, but not all iteration is synchronous
(like above). One example where multiple distinct arguments would be nice would be with native
forEach, which would work out-of-the-box with explicit parameters:

list.forEach do (item, i) {
    // Do something that requires both the current item and its index.
}

In the current formulation, this is what the syntax would look like:

foreach ({item, index} in list) {
    // Do something that requires both the current item and its index.
}

Which would desugar to:

foreach (list, function({item, index}) {
   // Do something that requires both the current item and its index.
});

Which foreach could use to pass parameters to the callee (IIUC your terminology):

function foreach(list, block) {
  for (let i = 0; i < list.length; i++) {
    block({item: list[i], index: i});
  }
}

Would that work?

@samuelgoto
Copy link
Owner

WIP DOM framework

I would love to hear more about your DOM framework :) This was very much started because I feel in love with Kotlin's examples of DSLs for DOM construction so hoping it will help this area.

Care to share any links?

@dead-claudia
Copy link
Author

dead-claudia commented Oct 31, 2017

@samuelgoto

In the current formulation, this is what the syntax would look like: [...]

I'm aware. I was responding with that awareness in mind.

Care to share any links?

It's currently private and purely local, since I'm only just now getting to the beginning stages of implementing the logic, and haven't implemented any tests (after spending literal months figuring out what I wanted the API to be).

Edit: I hided this inside a <details> element, to make it easier to scroll by.

Here's an example ripped off ofbased on Elm's radio buttons example:
import * as m from "my-framework/hyperscript"
import marked from "marked"

const Sizes = {
    Small: "0.8em",
    Medium: "1em",
    Large: "1.2em",
}

const Toggle = m.component((r, {change, name}) => {
    r.h("label[style.padding=20px]", {onclick() { change.send(name) }}, r => {
        r.h("input[type=radio][name=font-size]")
        r.t(name)
    })
})

const MyApp = m.component((r, {update}) => {
    const change = m.ref.cell("Medium")

    r.h("fieldset", r => {
        r.c(Toggle, {change, name: "Small"})
        r.c(Toggle, {change, name: "Medium"})
        r.c(Toggle, {change, name: "Large"})
    })

    r.h("div", {
        style: {fontSize: change.pipe(
            m.ref.map(name => Sizes[name])
        )},
        props: {innerHTML: update.pipe(
            m.ref.map(update => marked(update.content))
        )},
    })
})

m.render(document.getElementById("app"), r => {
    const Intro = `
# Anna Karenina

## Chapter 1

Happy families are all alike; every unhappy family is unhappy in its own way.

Everything was in confusion in the Oblonskys’ house. The wife had discovered
that the husband was carrying on an intrigue with a French girl, who had been a
governess in their family, and she had announced to her husband that she could
not go on living in the same house with him...
`

    r.c(MyApp, {update: m.ref.of({content: Intro})})
})

@dead-claudia
Copy link
Author

dead-claudia commented Oct 31, 2017

Edit: I hided this inside a <details> element, to make it easier to scroll by.

If I were to write it using this proposal, I'd probably do something like this:
import * as m from "my-framework/block"
import marked from "marked"

const Sizes = {
    Small: "0.8em",
    Medium: "1em",
    Large: "1.2em",
}

const Toggle = m.component do ({change, name}) {
    h("label[style.padding=20px]", {onclick() { change.send(name) }}) {
        h("input[type=radio][name=font-size]") {}
        t(name) {}
    }
}

const MyApp = m.component do ({update}) {
    const change = m.ref.cell("Medium")

    h("fieldset") {
        c(Toggle, {change, name: "Small"}) {}
        c(Toggle, {change, name: "Medium"}) {}
        c(Toggle, {change, name: "Large"}) {}
    }

    h("div", {
        style: {fontSize: change.pipe(
            m.ref.map(name => Sizes[name])
        )},
        props: {innerHTML: update.pipe(
            m.ref.map(update => marked(update.content))
        )},
    }) {}
}

m.render(document.getElementById("app")) {
    const Intro = `
# Anna Karenina

## Chapter 1

Happy families are all alike; every unhappy family is unhappy in its own way.

Everything was in confusion in the Oblonskys’ house. The wife had discovered
that the husband was carrying on an intrigue with a French girl, who had been a
governess in their family, and she had announced to her husband that she could
not go on living in the same house with him...
`

    c(MyApp, {update: m.ref.of({content: Intro})}) {}
}

Kotlin bindings, you could imagine, would look similar.

@samuelgoto
Copy link
Owner

What about the following?

const Toggle = m.component do ({change, name}) {
    label({style: {padding: 20px}}]) {
      ::onclick() { change.send(name) }})
        
       input({type: radio, name: font-size}) {
       }
       
       span(name) {}
    }
}

@dead-claudia
Copy link
Author

I've considered going a similar route to that, except I ran into a few glitches:

  1. It's unclear how to integrate custom components.
  2. It's unclear how to integrate custom events.
  3. I'd rather avoid introducing the overhead of a proxy for this to discern the difference between the two.

Of course, this is more of a hypothetical front-end, and I'm developing a shared backend you can write the front-end stuff based on. It is similar to incremental-dom and virtual-dom in that regard, and you could write your own front-end that works that way.

Mind if you could find me on Gitter, and we can talk more on this privately? I'd rather avoid polluting the issue further on this topic, since it's not even public yet.

@littledan
Copy link

Arguments seem pretty important to me, especially with how you have examples with arguments (e.g., under "C#'s foreach").

Bikeshed syntax: maybe it's odd, but could we reuse the arrow function arrow?

foreach(list) item => {
}

Otherwise I like the foreach (map) { |key, value| } syntax.

@samuelgoto
Copy link
Owner

samuelgoto commented Nov 7, 2017

I dislike ruby's foreach (map) { |key, value| } syntax, but I think

foreach(list) item => {
}

or

foreach(list) do (item) {
}

Is growing on me.

May I ask what are your first impressions / reservations for the in syntax (totally cool if the impressions are purely subjective/bikeshedding)? Doesn't that look more consistent with the current usage of

for (a in list) {
}

Don't you think it feels more natural to re-use that syntax/construct for params?

foreach (a in list) {
}

?

@littledan
Copy link

I like either of those too.

My immediate reaction to in is a little hesitant. It makes me think of a for-in loop, where things would be different in two ways:

  • You'd be assigning to an existing binding, rather than making a new binding (BAD--use a let)
  • You'd be iterating over object keys and up the prototype chain (BAD--use for-of)

Even though it's not supposed to be any of those things, it raises my subconscious JS linter flags.

@samuelgoto
Copy link
Owner

samuelgoto commented Nov 10, 2017

just as another data point, @erights also suggested the following syntax:

foreach(list) do (item) {
}

Which I think is a reasonable form and seems to map better to people's intuition than my original form. I'm going to update the text to reflect that (done).

@littledan
Copy link

SGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants