<< Back to previous view

[ASYNC-119] ClojureScript: combine cljs.core.async.macros and cljs.core.async Created: 15/Mar/15  Updated: 19/Aug/16

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: J. S. Choi Assignee: Unassigned
Resolution: Unresolved Votes: 7
Labels: enhancement

Attachments: Text File ASYNC-119.patch    


The macros in cljs.core.async.macros can now be moved into the cljs.core.async namespace, now that combined .cljs/.clj namespaces are possible in ClojureScript. This, along with ClojureScript 0.0-2755's recent improvements, would enable users to use `(require [cljs.core.async :refer [go go-loop ...])` without having to distinguish between functions and macros, and without having to use `require-macros` at all.

Comment by J. S. Choi [ 14/Oct/15 9:19 PM ]

ASYNC-142 (http://dev.clojure.org/jira/browse/ASYNC-142) proposes renaming the ClojureScript namespace from cljs.core.async to clojure.core.async, which would supersede this improvement.

Personally, I would love for ASYNC-142 to happen, though if it ends up being held back for a major change across all clojure.core projects, as Alex Miller suggested on its ticket, then this improvement may still be worth doing in the meantime.

Comment by Tim Gilbert [ 19/Aug/16 1:35 PM ]

There have been a few recent developments to ClojureScript that might make this a bit more feasible now.

Notably, the 1.9.216 ClojureScript will now import cljs.* namespaces which are referenced as clojure.* via CLJS-1692, and it will infer which referenced things from a namespace are macros versus functions via CLJS-1507.

One can currently import the functions in cljs.core.async using the same syntax as Clojure:

(ns my.app 
  (:require [clojure.core.async :refer [<! >!]]))

To get the macros, however, a separate (:require-macros) call is needed:

(ns my.app 
  (:require-macros [cljs.core.async.macros :refer [go go-loop]]))
  (:require [clojure.core.async :refer [<! >!]]))

If the macros were moved from cljs.core.async.macros into cljs.core.async, one could use the same syntax from either Clojure or ClojureScript:

(ns my.app 
  (:require [clojure.core.async :refer [<! >! go go-loop]]))

On the ClojureScript Slack channel David Nolen indicated that this would be a breaking change, and with questionable value relative to that. I think it might be worth talking about, though - in theory, at least, I could imagine an implementation that moves the macros into cljs.core.async and leaves aliases or shim versions around in the old cljs.core.async.macros namespace for backwards compatibility.

Comment by Juho Teperi [ 19/Aug/16 2:31 PM ]

Here is a patch which moves the macros but adds shim vars to the macros ns. The idea for shim vars has been take from Potemkin: https://github.com/ztellman/potemkin/blob/master/src/potemkin/namespaces.clj

There is one minor case where this will break user's code:

(:require-macros [cljs.core.async.macros :as a)
(:require [cljs.core.async :as a])

It has been possible to use same alias for macro and cljs namespace, but this won't work if macro namespace exists with the same name as cljs namespace. BUT I don't think this is a problem, because this has never been intended to be supported.

Most people probably use :require-macros with :refer, and this continues to work after this patch:

(:require-macros [cljs.core.async.macros :refer [go])
(:require [cljs.core.async :as a])

Tested with clojurescript 1.9.89 and 1.9.225.

[ASYNC-38] keep</> instead of map</> Created: 18/Nov/13  Updated: 02/Sep/14  Resolved: 02/Sep/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Leon Grapenthin Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: documentation, enhancement, errormsgs


One problem with using map< is when the supplied function returns nil. In such case (using the latest implementation from core.async [org.clojure/core.async ""]) one can take nil from a channel created with map<. This is otherwise only possible with closed channels. Putting nil on a channel normally throws an IllegalArgumentException.

With the current implementation of map< it is not possible to determine whether the source-channel was closed or the supplied function returned nil.

Notice that putting onto a channel created with map> throws an IllegalArgumentException when the supplied function returns nil as if you would put nil onto a channel.

My proposal is to add keep</> (where nil values returned from the supplied function are ignored and nothing is put) to the core library or to implement map</> as keep</> since having a real map</> instead of keep</> hardly makes sense when nil is not permitted anyways.

Comment by Leon Grapenthin [ 24/Apr/14 3:44 AM ]

It is still an issue in "" that you can only use impl.protocols/closed? to consistently determine whether a channel created with map</> was closed - if nil is one of your predicates return values.

Of course, you could use a predicate that never returns nil. But what should be the benefit of map</> being able to magically pass nil while everything else isn't?

Comment by Alex Miller [ 02/Sep/14 9:43 AM ]

All of the transformation functions (like map<) are deprecated and will go away to be replaced with applying transducers to channels.

Generated at Sat Oct 22 12:51:48 CDT 2016 using JIRA 4.4#649-r158309.