Skip to content

new: sugar.chainOn, chainEval #13245

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

Closed
wants to merge 5 commits into from

Conversation

timotheecour
Copy link
Member

@timotheecour timotheecour commented Jan 23, 2020

improvements over #13092

  • (minor) nnkPrefix gets transformed to nnkInfix, otherwise repr doesn't work (and it looks like a violation of nnkPrefix?)
  • (minor) renamed operateOn to chainOn
  • supports both statementlist-style and varargs style: a.chainOn(+= 10, mult2(), *= 100) for easy one-liners
    a.chainOn: # or `chainOn a:`
      += 4
      -= 5
    # new:
    a.chainOn(+= 10, mult2(), *= 100)

alternatives were considered in the forum involving ; eg:

on x: add("a"); add("b")
x.on.add("a").add("b")

but IMO this is better:

a.chainOn(+= 10, mult2(), *= 100)
  • supports field accesses
    There is no ambiguity here; infix operators x += expr imply a field access _.x += expr, whereas postfix operators += expr imply _ += expr
    type Foo = object
      x1, x2: int
    var foo: Foo
    foo.chainOn(initialize(), postprocess("foo"), x1 = 1, x1 += 3, x2 = 5)

also added chainEval

this is a simpler wrapper around chainOn that is used for returning expressions; it evaluates the lhs (once), applies the chain, and returns the result.
It's a quite natural addition.

doAssert (5+5).chainEval(*= 2, += 100) == ((5+5)*2) + 100
return expressionWithSideEffect("foo", bar).chainEval(*= 2, += 100, transform())

@timotheecour timotheecour changed the title new: sugar.chainOn new: sugar.chainOn, chainEval Jan 23, 2020
@Araq
Copy link
Member

Araq commented Jan 23, 2020

Excuse me if the question is silly (I'm tired) but does this support "dot chaining" (foo.on.add("a").add("b")) or not?

@timotheecour
Copy link
Member Author

timotheecour commented Jan 24, 2020

dot chaining as you suggest would have drawbacks:

  • no support for operators +=
  • no support for field access
  • ambiguity arising from whether you're using standard method call syntax or magical chained syntax (that adds hidden variable), eg:
foo.on.foo("a").toLower()

makes it impossible to call a proc toLower(a: string): string, and REQUIRES a proc toLower(result: var string) (which may not exist, and indeed doesn't for toLower)

instead, this PR allows maximum flexibility and we can mix method call syntax and magic chaining with 0 ambiguity, see example I added:

      doAssert 10.chainEval(*= 2).float.chainEval(*= 3.5) == float(10*2)*3.5
      import std/[strutils, algorithm]
      doAssert 10.chainEval(*= 2).`$`.chainEval(add("cba"), sort()).toLower() == "02abc"

all arguments inside chainEval(lhs, ...) will use magic chaining, all arguments outside will use regular method call syntax; no surprises here.

@Araq
Copy link
Member

Araq commented Feb 12, 2020

See nim-lang/RFCs#192 for a discussion.

@Araq
Copy link
Member

Araq commented Mar 11, 2020

Instead we got with and dup.

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

Successfully merging this pull request may close these issues.

2 participants