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

New syntax proposal: Constructor Cascade (returns the cascadee) #172

Closed
qqueue opened this issue Oct 5, 2012 · 4 comments
Closed

New syntax proposal: Constructor Cascade (returns the cascadee) #172

qqueue opened this issue Oct 5, 2012 · 4 comments

Comments

@qqueue
Copy link

qqueue commented Oct 5, 2012

I've got a fair amount of code that looks like this:

head = document.createElement \head
style = document.createElement \style
  &id = \html5chan-style
  &textContent =
    '''
    %hakase.css%
    '''
head.appendChild style

title = document.createElement \title
  &textContent = board.title
head.appendChild title
html.appendChild head

or more purely, like this:

thing = new Thing
  &foo = 'bar'
  &baz = quux 'stuff'
something-with thing

where some of the code initializes and mutates an object just to pass it into another function (or return it). When available, I usually use a full constructor:

something-with new Thing foo: \bar baz: quux \stuff

But some constructors, e.g. DOM Image, have stupid arguments (no src), so an extra line of initialization is necessary.

I know I can use new with a block to create the new function() {...} form, but that doesn't work with Image, and it introduces overhead. Thus, my straw man is:

Constructor Cascade

Similar to cascade, but expression returns the original reference (after execution of the block) instead of the result of the last expression in the block.

fn = -> construct new Image
  &src = 'image.jpg'

document.body.appendChild do
  construct document.createElement \div
    &id = \stuff
    &classList.add \things
    &style
      &display = \block
    &textContent = 'are you a wizard'

=>

var img, $x,$y;
img = function() {
  var $y = new Image
  $y.src = 'image.jpg'
  return $y
}

$x = document.createElement('div')
$x.id = 'stuff'
$x.classList.add('things')
$y = $x.style
$y.display = 'block'
$x.textContent = 'are you a wizard'
document.body.appendChild($x)

Advantages

  • Avoids needing an extra reference to a variable used only as an argument
  • Cuts down on the verbosity of creating DOM trees, without any function calling overhead
  • Avoids an extra return this at the end of a function, e.g. when using with new XMLHttpRequest
  • Extends cascade to cover the other use of "fluent interface"-style chaining APIs, e.g: $(body).append($('<p>').text('just look at all this overhead!'))

Problems

  • Couldn't think of a better symbol/keyword than construct
  • Complicates the meaning of & even more
  • Changes the order of code in the compiled js compared to the source
@satyr
Copy link
Owner

satyr commented Oct 5, 2012

I have to agree that a cascade expression should evaluates to the cascadee value. While maximally minimal, the current syntax seems to miss the major use cases by limiting itself to the top-level.

We add no new keywords as a policy, so we may have to introduce some new symbol operator. Say, +>:

something-with new Thing +>
  &foo = 'bar'
  &baz = quux 'stuff'

And/or we can make with return the target by default:

something-with with new Thing
  @foo = 'bar'
  @baz = quux 'stuff'

@qqueue
Copy link
Author

qqueue commented Oct 5, 2012

Hmm, is it even worth keeping with's current behavior as sugar for .call(thing)? I can't imagine many use cases where having the actual IEFE would be preferrable over the more performant cascade. I mean, with's example in the docs could be completely replaced with cascade. If one actually needs a new scope, let makes more sense than with anyway.

Using with as the cascade-that-evaluates-to-cascadee operator avoids using creating any more reserved words, and it "reads" better than +>, IMO.

For the times that you do need to set the context for an IEFE, you could just special-case let to detect constructs like let @ = something or let this = something to set the context appropriately.

@satyr
Copy link
Owner

satyr commented Oct 5, 2012

Great point.

The purpose of with was exactly the cascade-ish construct. Now that we added an actual cascade, we should reconsider its raison d'etre.

So the proposal becomes:

  • Make cascade return cascadee.

  • Change with to an expression version of cascade.

    head.appendChild do
      with document.createElement \title
        &textContent = btitle
    

      var x$;
      head.appendChild((x$ = document.createElement('title'), x$.textContent = btitle, x$))
    
  • Make let support this-substitution again.

    let this = foo, bar = baz
      ...
    
    # as:
    
    ((bar) ->
      ...
    )call foo, baz
    

@qqueue
Copy link
Author

qqueue commented Oct 5, 2012

That looks fine to me, though the readability of the compiled js suffers a bit with the comma expression. Similar to #115, it'd be nicer if it compiled to

head.appendChild(
  (x$ = document.createElement('title')
  , x$.textContent = btitle
  , x$))

Just a minor issue.

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

2 participants