[ClojureScript]: Breaking change coming WRT object property access syntax

87 views
Skip to first unread message

Fogus

unread,
Oct 14, 2011, 3:28:39 PM10/14/11
to Clojure Dev
The ticket http://dev.clojure.org/jira/browse/CLJS-89 and the design
page http://dev.clojure.org/display/design/Unified+ClojureScript+and+Clojure+field+access+syntax
describe the details of the change in ClojureScript. Can anyone see
any downsides to this change from a unifying perspective (between
Clojure and ClojureScript)?

Thanks.

David Nolen

unread,
Oct 14, 2011, 3:33:17 PM10/14/11
to cloju...@googlegroups.com
Not having written significant production code that relies on the previous behavior, my opinions aren't strong on this. But given that people seem to complain almost immediately when CLJS is broken (as I did with with the original CLJS-84 fix), quite a few people might already by using ClojureScript in production.

Most of these people are not on the dev list as far as I can tell. Does it make sense to bring this up there as well?

David


--
You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
To post to this group, send email to cloju...@googlegroups.com.
To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.


Michael Fogus

unread,
Oct 14, 2011, 3:36:47 PM10/14/11
to cloju...@googlegroups.com
Yes.  Breaking changes stink to high-heaven, but my view is that it's better now than later.  



--
-- http://fogus.me
-- http://github.com/fogus
--

Sean Corfield

unread,
Oct 14, 2011, 5:33:28 PM10/14/11
to cloju...@googlegroups.com

Just to clarify, currently Clojure has:

(.p o) ;=> a property access if p is a property
(. o p) ;=> a property access if p is a property

It looks like the proposal will remove that and treat both as method
calls regardless - or am I misunderstanding the proposed change to
Clojure?

I agree that (. o :p) is clearer for property access (and it would be
nice to be portable between CLJ and CLJS) - so I'm in favor of the
change.

Could a warning be added to the (Clojure) compiler to flag (.p o) and
(. o p) if p is a property? - to encourage folks to switch to (. o :p)
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/
Railo Technologies, Inc. -- http://www.getrailo.com/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)

David Nolen

unread,
Oct 14, 2011, 5:39:31 PM10/14/11
to cloju...@googlegroups.com
On Fri, Oct 14, 2011 at 5:33 PM, Sean Corfield <seanco...@gmail.com> wrote:
On Fri, Oct 14, 2011 at 12:28 PM, Fogus <mef...@gmail.com> wrote:
> The ticket http://dev.clojure.org/jira/browse/CLJS-89 and the design
> page http://dev.clojure.org/display/design/Unified+ClojureScript+and+Clojure+field+access+syntax
> describe the details of the change in ClojureScript.  Can anyone see
> any downsides to this change from a unifying perspective (between
> Clojure and ClojureScript)?

Just to clarify, currently Clojure has:

(.p o)           ;=> a property access if p is a property
(. o p)          ;=> a property access if p is a property

It looks like the proposal will remove that and treat both as method
calls regardless - or am I misunderstanding the proposed change to
Clojure?

To change this in Clojure would be yet another breaking change, right? It seems like unification would then be quite difficult between Clojure and ClojureScript with breaking changes to both.

I wonder if the solution here is just to be very clear in the documentation about ClojureScript. To honest I was confused by this in ClojureScript all of 5 minutes. It would be great to hear what the other active ClojureScript users think! Chime in folks!

David

Michael Fogus

unread,
Oct 14, 2011, 5:43:12 PM10/14/11
to cloju...@googlegroups.com

Nothing will change about Clojure except that. (. o :p) will be smarter about avoiding reflection.  The difference in the other cases in ClojureScript is due entirely to the "function property" problem.

Michael Fogus

unread,
Oct 14, 2011, 5:47:59 PM10/14/11
to cloju...@googlegroups.com

There is no way to avoid a difference in the (.m o) and (. o m) cases.  But you're right that clearer docs for those differences will help.

--

Kevin Downey

unread,
Oct 14, 2011, 5:51:05 PM10/14/11
to cloju...@googlegroups.com
1. it would certainly get rid of the hoops a clojure compiler has to
go through to disambiguate the two cases.

2. it adds syntax, which is regrettable. (which is just the flip side of 1)

the difference between field access and function application is
tricky, with clojure's native data (x y) could be either depending on
the value of x or y.

have you thought about adding a special form that only does field
access? get-native-field or something?

seems cleaner and allows for . to be all about method calls in the (future)

> --
> You received this message because you are subscribed to the Google Groups
> "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to
> clojure-dev...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/clojure-dev?hl=en.
>

--
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?

Chris Granger

unread,
Oct 14, 2011, 6:09:16 PM10/14/11
to cloju...@googlegroups.com
I use CLJS a fair amount, and I realllllly don't like this change. For one, I don't really care about portability here since interop code like this will never make sense in both clj and cljs since it's platform dependent.

I'm with David on this one, I was like "oh that's weird" for like 5 minutes. The solution is to just always use the (. foo (bar)) syntax when you mean a method (which is actually clearer to me anyways?) and the (.bar foo) syntax when you want a property.

Cheers,
Chris.

Baishampayan Ghose

unread,
Oct 14, 2011, 6:16:37 PM10/14/11
to cloju...@googlegroups.com
On Sat, Oct 15, 2011 at 3:39 AM, Chris Granger <ibd...@gmail.com> wrote:
> I'm with David on this one, I was like "oh that's weird" for like 5 minutes.
> The solution is to just always use the (. foo (bar)) syntax when you mean a
> method (which is actually clearer to me anyways?) and the (.bar foo) syntax
> when you want a property.

+1 on this. I am personally in favour of keeping the current style
since it's not broken.

Regards,
BG

--
Baishampayan Ghose
b.ghose at gmail.com

David Nolen

unread,
Oct 14, 2011, 6:18:56 PM10/14/11
to cloju...@googlegroups.com
On Fri, Oct 14, 2011 at 6:09 PM, Chris Granger <ibd...@gmail.com> wrote:
I use CLJS a fair amount, and I realllllly don't like this change. For one, I don't really care about portability here since interop code like this will never make sense in both clj and cljs since it's platform dependent.

This is a good point. (. foo ...) is only about interop. JS and Java - never the twain shall meet.

David 

Michael Fogus

unread,
Oct 14, 2011, 6:30:45 PM10/14/11
to cloju...@googlegroups.com

> reallllllly don't like this change

Do you mind going into more detail?

Michael Fogus

unread,
Oct 14, 2011, 6:30:45 PM10/14/11
to cloju...@googlegroups.com

Just to be clear.  Just because it works doesn't mean it's optimal.  Just to be doubly clear:

- No breaking changes happen with Clojure
- if you're using (. o (m)) with or without args in ClojureScript then nothing breaks.
- If you want to be explicit about field access in Clojure or ClojureScript then (. o :p) is the syntax (and in the latter, the only syntax)

David Nolen

unread,
Oct 14, 2011, 7:12:53 PM10/14/11
to cloju...@googlegroups.com
The proposed change is not optimal and I think it clashes with the realities of JavaScript interop.

(.property foo)

Currently gives us a notion of "place", that means we can set it:

(set! (.property foo) "bar")

This convention is quite common in many JavaScript APIs, for example pretty everything in the browser:

(set! (.id foo) "my-css-id"))
(set! (.fillStyle ctxt) "rgb(255, 150, 0)")

Now compare to the proposed change:

(set! (. foo :id) "my-css-id"))
(set! (. ctxt :fillStyle) "rgb(255, 150, 0)")

I don't see any win. Any proposed change should account for the fact that getters / setters are not a convention in JS and many, many APIs expect direct field access.

David

On Fri, Oct 14, 2011 at 6:30 PM, Michael Fogus <mef...@gmail.com> wrote:

> reallllllly don't like this change

Do you mind going into more detail?

--

David Nolen

unread,
Oct 14, 2011, 7:29:59 PM10/14/11
to cloju...@googlegroups.com
Also I note that ClojureScript itself uses the following conventions freely when dealing with properties:

(set! foo.bar.baz ...)
(+ foo.bar.baz 1)

Examples like these illustrate that interop is interop, and the proposed unification doesn't actually improve any semantics for ClojureScript. It simply addresses a very minor source of potential confusion for *Clojure* users familiar w/ *Clojure* interop conventions.

David

Michael Fogus

unread,
Oct 14, 2011, 7:30:44 PM10/14/11
to cloju...@googlegroups.com

Now that is the kind of feedback that I was hoping for... and it's pretty darn compelling.

Michael Fogus

unread,
Oct 14, 2011, 8:03:16 PM10/14/11
to cloju...@googlegroups.com

Well whether ClojureScript should do that is another thread.  In general we should be careful to hold even the core source up as best if there is potentially a better way. 

David Nolen

unread,
Oct 14, 2011, 8:25:23 PM10/14/11
to cloju...@googlegroups.com
On Fri, Oct 14, 2011 at 8:03 PM, Michael Fogus <mef...@gmail.com> wrote:

Well whether ClojureScript should do that is another thread.  In general we should be careful to hold even the core source up as best if there is potentially a better way.

Sure but I just want to make sure that interop decisions are weighed against the point of diminishing return around abstracting away interop. I think plenty of people feel that pain already in Clojure. I see no reason to go down that road with ClojureScript.

JavaScript interop should be dead simple. Anything that creates complexity around that should be eyed with suspicion.

Changing:

(set! foo.bar.baz.woz 1)

to:

(set! (.woz (.baz (.bar foo))) 1)

Isn't helping or improving anything IMO. It's just more tedious to type.

David 

Michael Fogus

unread,
Oct 14, 2011, 9:03:25 PM10/14/11
to cloju...@googlegroups.com

> (set! (.woz (.baz (.bar foo))) 1)

Yikes! Where did that come from?  I think we can all agree to avoid that.

David Nolen

unread,
Oct 14, 2011, 9:04:40 PM10/14/11
to cloju...@googlegroups.com
Good :)

On Fri, Oct 14, 2011 at 9:03 PM, Michael Fogus <mef...@gmail.com> wrote:

> (set! (.woz (.baz (.bar foo))) 1)

Yikes! Where did that come from?  I think we can all agree to avoid that.

--

Devin Walters

unread,
Oct 15, 2011, 12:29:29 AM10/15/11
to cloju...@googlegroups.com, cloju...@googlegroups.com
If this confused you for 5 minutes it is likely to confuse others significantly longer. That is a gut feeling, and certainly not a rule. I think it's worth considering the cognitive load for a beginner v. Dnolen. Just saying...

Sent via mobile
--

Devin Walters

unread,
Oct 15, 2011, 12:34:58 AM10/15/11
to cloju...@googlegroups.com, cloju...@googlegroups.com
Minor disagreement with you there: it's easier to sell clojurescript as an extension of cljs and not as a separate language with /some/ clojure semantics.

Sent via mobile

David Nolen

unread,
Oct 15, 2011, 12:36:53 AM10/15/11
to cloju...@googlegroups.com
Ignore the opinions of people who have done at lot of JavaScript at your own peril. Good for beginners does not mean no pain for everyone else.

Laurent PETIT

unread,
Oct 15, 2011, 8:29:10 AM10/15/11
to cloju...@googlegroups.com
Sorry for being late in the discussion, but ...

Why couldn't javascript field access interop be superseded by
keyword-like call, as is e.g. the case for records ?

(. foo :bar) => (:bar foo)

?

2011/10/14 Fogus <mef...@gmail.com>:

Rich Hickey

unread,
Oct 15, 2011, 8:56:39 AM10/15/11
to cloju...@googlegroups.com

For early users, the experience was nearly universal:

1) They expected (.foo x) to 'call' foo, if foo was a 'method' (not really having thought through that there are no true methods in JS, nor any way to disambiguate as there is in Java))

2) They weren't even aware of Clojure's (. x (foo)) syntax, and wouldn't have guessed to try it.

3) Once shown (. x (foo)) they said - "ick! grumble, grumble"

So, it was considered a wart and this proposes to address it. While it may be the case that current ClojureScript users have inured themselves to it, I doubt the initial experience will be much different in the future.

However, if no one cares, we can work on something more important, and try to preclude the stumbles via documentation. The current approach is the best I could come up with, and I'm willing to stick with it.

But bear in mind, fixing it later will become an impossibility. We will only be in this early alpha stage once.

Rich

Everyone: note also - "I'm currently using it in production" is not a valid argument against changes at this time. CLJS, as anything else, simply must go through a period of malleability in order to become great. It has been plainly advertised as being in an early state, and by using it you have implicitly agreed to roll with any changes, in exchange for earlier access. If you can't accept that, then don't use it in production.

David Nolen

unread,
Oct 15, 2011, 10:25:59 AM10/15/11
to cloju...@googlegroups.com
On Sat, Oct 15, 2011 at 8:56 AM, Rich Hickey <richh...@gmail.com> wrote:
For early users, the experience was nearly universal:

1) They expected (.foo x) to 'call' foo, if foo was a 'method' (not really having thought through that there are no true methods in JS, nor any way to disambiguate as there is in Java))

2) They weren't even aware of Clojure's (. x (foo)) syntax, and wouldn't have guessed to try it.

3) Once shown (. x (foo)) they said - "ick! grumble, grumble"

So, it was considered a wart and this proposes to address it. While it may be the case that current ClojureScript users have inured themselves to it, I doubt the initial experience will be much different in the future.

However, if no one cares, we can work on something more important, and try to preclude the stumbles via documentation. The current approach is the best I could come up with, and I'm willing to stick with it.

I agree that if we're going to change it we have to change it now. If we do change it are we ok w/ losing an ok syntax for setting properties? Or do we expect people to do the following?
 
(. foo :bar) ;; accessing
(set! foo.bar 1) ;; setting

David 

Rich Hickey

unread,
Oct 15, 2011, 10:40:07 AM10/15/11
to cloju...@googlegroups.com

It is an orthogonal question as to what the behavior of set! should be given any particular form. I'm not sure what dictates we lose anything.

Rich

David Nolen

unread,
Oct 15, 2011, 11:00:57 AM10/15/11
to cloju...@googlegroups.com
On Sat, Oct 15, 2011 at 10:40 AM, Rich Hickey <richh...@gmail.com> wrote:
It is an orthogonal question as to what the behavior of set! should be given any particular form. I'm not sure what dictates we lose anything.

Rich

It's my JavaScript bias - property setting / getting are closely related. They happen to be closely related in CLJS at the moment.

It wasn't clear to me that the behavior of set! also needs to be sorted out. If that's so, I'm less concerned w/ the change.

David

Rich Hickey

unread,
Oct 15, 2011, 2:21:24 PM10/15/11
to cloju...@googlegroups.com
Well, they should be considered together, but the lack of quotes leaves me wondering what exactly you were concerned about? Do you have a proposal for set! ?

Rich

David Nolen

unread,
Oct 15, 2011, 2:49:35 PM10/15/11
to cloju...@googlegroups.com
On Sat, Oct 15, 2011 at 2:21 PM, Rich Hickey <richh...@gmail.com> wrote:
Well, they should be considered together, but the lack of quotes leaves me wondering what exactly you were concerned about? Do you have a proposal for set! ?

Rich

Heh, I wasn't concerned so much as I was wondering if anyone else was. I'm OK with how set! currently works.

David 

David Nolen

unread,
Oct 15, 2011, 3:12:18 PM10/15/11
to cloju...@googlegroups.com
Talking with Chris Granger on IRC, the aesthetics of:

(. foo :bar)

Leave something to be desired.

We already have a convention around low-level operations be preceded with a "-". What about a -get compiler macro?

(-get foo bar)

Then . only means method call.

David

On Sat, Oct 15, 2011 at 2:21 PM, Rich Hickey <richh...@gmail.com> wrote:

Chris Granger

unread,
Oct 15, 2011, 4:18:44 PM10/15/11
to cloju...@googlegroups.com
Advantages:
  • No new special syntax for an issue that is platform specific.
  • Reduces cognitive load:
    • No syntax
    • Continues to map "symbols" to Clojure symbols, instead of introducing the concept of a keyword (which won't exist in most hosts)
    • (.* x) always means execute a function, which is internally consistent with the semantics of (some-symbol x)
  • Allows for greater flexibility in handling host issues around this space in the future (we set the semantics of this method without worrying about trying to fit into what (.* x) already means).
Cheers,
Chris.

Luc Prefontaine

unread,
Oct 15, 2011, 4:22:21 PM10/15/11
to cloju...@googlegroups.com
+1, .

Luc P.

--
Luc P.

================
The rabid Muppet

Rich Hickey

unread,
Oct 15, 2011, 6:41:11 PM10/15/11
to cloju...@googlegroups.com
I would definitely try to pursue something more concise.

Remember, you are trying to sell this to people who were writing foo.bar - the parens alone are a big hurdle, everything we add beyond that is a tough sell.

This is something users would have to write frequently. I rarely write -anything in Clojure, so I wouldn't call it a convention, nor idiomatic.

Please remember ClojureScript is Clojure hosted on JavaScript. While host targets might be different, that doesn't mean each host should have different syntax for the same things (here, field access). Also note it doesn't mean there is no hope for portable host interop. To the extent you could make like-named shims for some host functionality, you could write portable host-acccessing code.

Finally note the 'point' of having Clojure run on multiple hosts, while not complete portability, is that your skills transfer. If host interop were different everywhere that becomes less true. E.g., you couldn't write portable macros that manipulate interop forms.

Whatever we come up with should work in Clojure too. (. foo :bar) happens to mostly work already. That doesn't mean it should win, but the above considerations apply.

This discussion highlights the fact that you don't design things like this on a mailing list by firing off ideas and +1ing them into consensus. Somewhere the considerations need to be enumerated and any suggestions measured against them.

Fogus's page is a start:

http://dev.clojure.org/display/design/Unified+ClojureScript+and+Clojure+field+access+syntax

and there are also some ideas on this topic in my original design notes:

https://raw.github.com/clojure/clojurescript/reader-fixes/devnotes/cljs.org

Rich

Luc Prefontaine

unread,
Oct 15, 2011, 8:29:58 PM10/15/11
to cloju...@googlegroups.com
I reviewed Fogus's page, your design notes and the whole thread,
including the one on the clojure list.

My initial reaction was biased toward my own reality (JVM, frequent Java interop).
However this cannot be the only stick yard I should use to favor (-get foo bar)
versus (. foo :bar).

My main unexpressed concerns were the impacts on the actual Java interop in Clojure.
If (. foo bar) still works in Clojure for a while (18 months ?) then
(. foo :bar) has some sex appeal to me and I can live with that.
A meaningful compiler message when the : is missing would also help :)

Two people mentioned (:bar foo) but I expect you have valid reasons not to
pursue in this direction ?

Luc

--

Rich Hickey

unread,
Oct 15, 2011, 8:33:52 PM10/15/11
to cloju...@googlegroups.com
To be perfectly clear, nothing is going to be removed from Clojure in this area. Something *might* be added that will work the same in Clojure and ClojureScript.

Rich

Michael Fogus

unread,
Oct 15, 2011, 8:40:24 PM10/15/11
to cloju...@googlegroups.com

Thanks for jumping in Rich.  This seems to be a point of confusion.  I'll go back to the design page and make sure this is super-mega-clear.

Luc Prefontaine

unread,
Oct 15, 2011, 10:25:30 PM10/15/11
to cloju...@googlegroups.com

Then you have my 100% support for the keyword approach :)

Luc P.

On Sat, 15 Oct 2011 20:33:52 -0400

Reply all
Reply to author
Forward
0 new messages