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

added operateOn to sugar.nim to give Nim the chaining mechanism it de… #13092

Merged
merged 5 commits into from
Feb 26, 2020

Conversation

Araq
Copy link
Member

@Araq Araq commented Jan 9, 2020

…serves

@Araq
Copy link
Member Author

Araq commented Jan 9, 2020

I probably got it completely wrong but it's to start a discussion.

@treeform
Copy link
Contributor

treeform commented Jan 9, 2020

Is there an example on how to use it?

@Araq
Copy link
Member Author

Araq commented Jan 9, 2020

      var x = "yay"
      operateOn x:
        add "abc"
        add "efg"
      doAssert x == "yayabcefg"

      var a = 44
      operateOn a:
        += 4
        -= 5
      doAssert a == 43

@juancarlospaco
Copy link
Collaborator

juancarlospaco commented Jan 10, 2020

What about chainOn for chaining on instead of operateOn ?. 🤔

@alehander92
Copy link
Contributor

or just on? so you can : a.on.add(..).add(..) (and do the on: for +)

@juancarlospaco
Copy link
Collaborator

on is true also. 🤔

@zedeus
Copy link
Contributor

zedeus commented Jan 10, 2020

on is too short imo, likely to clash with object fields or event systems. I'd prefer chainOn

@juancarlospaco
Copy link
Collaborator

chainOn is kind of self-explanatory and short. "which function does chain?. chainOn" 🙂

@ducdetronquito
Copy link
Contributor

I found this proposal on the forum thanks to Araq.

What is the reasoning behind this sugar syntax ?
Is there some production code where something like a builder pattern is not enough to chain procedures ?

In a small web framework I am working on, I wanted to chain procedures to define callbacks for multiple HTTP methods on the same URL.

Example:

import phoon

var app = App()

app.route("/hacks")
    .get(
        proc (ctx: Context) {.async.} =
            ctx.response.body("I handle GET requests")
    )
    .patch(
        proc (ctx: Context) {.async.} =
            ctx.response.body("I handle PATCH requests")
    )
    .delete(
        proc (ctx: Context) {.async.} =
            ctx.response.body("I handle DELETE requests")
    )

And wit the sugar syntax, it would become:

import phoon
import sugar
var app = App()

var route = app.route("/hacks")
chainOn route:
    get(
        proc (ctx: Context) {.async.} =
            ctx.response.body("I handle GET requests")
    )
    .patch(
        proc (ctx: Context) {.async.} =
            ctx.response.body("I handle PATCH requests")
    )
    .delete(
        proc (ctx: Context) {.async.} =
            ctx.response.body("I handle DELETE requests")
    )

I am genuinely wondering if this sugar is worth it, but I would be glad to be proven wrong :)

@SolitudeSF
Copy link
Contributor

builder pattern is an awful hack that compensates lack of such sugar

@treeform
Copy link
Contributor

Your example is using returns (builder pattern) to return the same router over and over again. Many of us think this is not that good because it confuses returns which should return useful info with making the syntax look nice.

chainOn trying to fix this example:

var app = App()

var route = app.route("/hacks")
route.get(
  proc (ctx: Context) {.async.} =
    ctx.response.body("I handle GET requests")
)
route.patch(
  proc (ctx: Context) {.async.} =
    ctx.response.body("I handle PATCH requests")
)
route.delete(
  proc (ctx: Context) {.async.} =
    ctx.response.body("I handle DELETE requests")
)

@planetis-m
Copy link
Contributor

...and it could be written as:

var route = app.route("/hacks")
operateOn(route):
  get:
    proc (ctx: Context) {.async.} =
      ctx.response.body("I handle GET requests")
  patch:
    proc (ctx: Context) {.async.} =
      ctx.response.body("I handle PATCH requests")
  delete:
    proc (ctx: Context) {.async.} =
      ctx.response.body("I handle DELETE requests"

Please ship it :D

@planetis-m
Copy link
Contributor

How about turning assignments to fields?

There is also https://github.com/citycide/cascade which is more advanced but slightly different (it returns a type). Maybe include that macro to the stdlib? cc @citycide

@haltcase
Copy link
Contributor

haltcase commented Jan 22, 2020

@B3liever

This does work similarly to cascade, for reference it'd be something like this:

import cascade

var app = App()

var route = cascade app.route("/hacks"):
  get(
    proc (ctx: Context) {.async.} =
      ctx.response.body("I handle GET requests")
  )

  patch(
    proc (ctx: Context) {.async.} =
      ctx.response.body("I handle PATCH requests")
  )

  delete(
    proc (ctx: Context) {.async.} =
      ctx.response.body("I handle DELETE requests")
  )

Though like you said, cascade supports more than just chaining.

@Araq Araq merged commit d55bbef into devel Feb 26, 2020
@Araq Araq deleted the araq-operate-on branch February 26, 2020 19:36
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.

9 participants