This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-04-04
Channels
- # architecture (20)
- # aws (8)
- # beginners (13)
- # boot (9)
- # cider (80)
- # cljs-dev (69)
- # cljsrn (7)
- # clojure (243)
- # clojure-dusseldorf (8)
- # clojure-italy (5)
- # clojure-norway (3)
- # clojure-poland (57)
- # clojure-russia (10)
- # clojure-shanghai (2)
- # clojure-spec (11)
- # clojure-uk (50)
- # clojurescript (198)
- # core-async (11)
- # crypto (2)
- # cursive (14)
- # datomic (17)
- # figwheel (8)
- # garden (7)
- # hoplon (8)
- # incanter (4)
- # jobs (1)
- # leiningen (1)
- # liberator (38)
- # lumo (28)
- # om (55)
- # onyx (10)
- # pedestal (13)
- # perun (20)
- # re-frame (1)
- # reagent (16)
- # ring-swagger (9)
- # spacemacs (11)
- # test-check (9)
- # unrepl (43)
- # untangled (163)
- # yada (8)
I attached the patch I've been trying to an "Outward function type hint propagation" JIRA: http://dev.clojure.org/jira/browse/CLJS-1997
interesting how small the patch is 🙂
Yes—it could be even smaller (but a little more aggressive) if it just dropped the inferred type directly into :ret-tag
. But, yes—I was surprised the compiler is already arranged to support it.
The patch not only has potential perf benefits (eliding the truth check), but it could help catch more errors via type propagation:
cljs.user=> (defn f [] "h")
#'cljs.user/f
cljs.user=> (+ (f) 1)
^
WARNING: cljs.core/+, all arguments must be numbers, got [string number] instead. at line 1
"h1"
So it seems that Array.prototype.join
already does work properly with nil
+ js/undefined
:
(js* "[~{},~{},~{}].join('')" nil "foo" js/undefined)
I'd like to propose to change the str
macro to:
(let [pre-cat (reduce
(fn [xs x]
;; If this and the last is a string, we can pre-concat:
(if (and (string? x) (string? (last xs)))
(conj (pop xs) (str (last xs) x))
(conj xs x)))
[]
args)]
;; If all that's left is a single string we can just emit that:
(if (and (= 1 (count pre-cat)) (string? (first pre-cat)))
(first pre-cat)
(apply core/list 'js/goog.string.buildString pre-cat)))
That'd also allow people to just use (str "foo" "bar")
to break up long string over multiple lines.
Similar for str
function. There is
goog.string.makeSafe = function(obj) {
return obj == null ? '' : String(obj);
};
@rauh there is a lot of history behind the str
macro, see http://dev.clojure.org/jira/browse/CLJS-890
and FWIW the closure compiler will do the optimization you proposed (if I understand the intent correctly)
I don't see google closure compiler pre-concatenating strings unless I use js's +
-operator
I did this recently http://dev.clojure.org/jira/browse/CLJS-1879 which let the closure compiler inline more str
related things
Yeah I so that ticket. But strange that the current impl is faster than buildString. Their docstring says the opposite.
I did only this minimal change because I was afraid of the history of CLJS-890
, but it provided most of the benefits
Ok I see, lots of edge cases 😕. Though:
1. The calls to the 1-arity version don't get optimized away even when passing a string literal
2. Why again .join("")
call to concat the resulting strings when we already know that we have only strings. (So +
should be safe to use, even for Safari)
Ie, why not:
(core/let [strs (core/->> (mapv (fn [x]
(if (string? x)
"~{}"
"cljs.core.str.cljs$core$IFn$_invoke$arity$1(~{})"))
xs)
(interpose "+")
(apply core/str))]
(apply list 'js* (core/str "(" strs ")") xs))
GCC should concat the constants for us and we don't emit unnecessary calls to the arity$1
str function.
so if I understand correctly you want (str "foo" "bar")
to emit ["foo", "bar"].join("")
instead of [cljs.core.str.cljs$core$IFn$_invoke$arity$1("foo"), cljs.core.str.cljs$core$IFn$_invoke$arity$1("bar")].join("")
eg the proposed would result in: (cljs.core.str.cljs$core$IFn$_invoke$arity$1(ns) + "/" + cljs.core.str.cljs$core$IFn$_invoke$arity$1(name))
Try:
function str(x) {
if((x == null)){
return "";
} else {
return [x].join("");
}
}
console.log([str("foo"), str("bar")].join(""));
See the pseudo advanced compilation. It's littered with cljs.core.str.cljs$core$IFn$_invoke$arity$1("some string")
that should really be optimized by the macro then, I was sure closure took care of that
function str(x) {
return [x].join("");
}
console.log([str("foo"), str("bar")].join(""));
I still think we should stop worrying about Safari 6.0.5. Even more so now since 2+ years have passed
I have an ancient mountain lion mac and even it uses safari 6.1.x, which does not have that str bug
Agreed. This also indicates it can be safely dropped: http://caniuse.com/usage-table
@dnolen I don't propose changing the behavior. The macro change would result in smaller & faster code. So IMO a win win without any downside.
@favila that doesn’t really tell us anything - we fixed it for Safari so we don’t get reports about older iOS
@dnolen I just tested it on ff+chrome. It looks like chrome prefers [].join()
. So I'd say stick with array.join
but I'd still vote for omitting the str$arity$1
call if it's already a string.