gkz / LiveScript

LiveScript is a language which compiles to JavaScript. It has a straightforward mapping to JavaScript and allows you to write expressive code devoid of repetitive boilerplate. While LiveScript adds many features to assist in functional style programming, it also has many improvements for object oriented and imperative programming.
http://livescript.net
MIT License
2.32k stars 155 forks source link

Broken type of clone of object using "with" keyword #717

Open haskellcamargo opened 9 years ago

haskellcamargo commented 9 years ago

There is a small issue that happens on cloning objects using with keyword: it changes the type of the instance of that object and this can have compatibily issues with some libraries, such as jQuery UI.

See the example:

export accordion-default-settings =
  header: "> div > h4"
  collapsible: yes
  before-activate: before-activate
  height-style: \content

This will generate an object containing the following:

1

The with keyword clones an object and changes the passed properties, it should have no side effects, such as affect the type of the instance of the variable.

Being accordionParentSettings the following, we have:

export accordion-parent-settings =
  accordion-default-settings with header: "> div > h3"

This will also generate an object, but an instance of fun:

2

This wasn't supposed to happen, as much as some libraries check the instance of the object. This will be incompatible with jQuery UI plugins and other smaller libraries, taking account they must assert the instance.

3

Our second value was supposed to be also a native Object, not a fun.

I checked and this also happens with the example in the documentation:

girl = {name: \hanna, age: 22}
guy  = girl with name: \john
guy  #=> {name: 'john',  age: 22}
# the above result include the object's prototype
# in the result - the actual JSON: {name: 'john'}
girl #=> {name: 'hanna', age: 22}

Inspecting:

4

ymeine commented 9 years ago

I guess the current implementation using a generated constructor to create the prototype chain was made in order to support a wider range of platforms.

Without this compatibility concern, using the API Object.create from JavaScript would solve the issue.


However while playing with that, I faced something weird.

Note that I tested in Chrome, since the development tools of Firefox were always showing Object as the type, not fun.

If you do:

a = {}
b = a with {}
console.log b

you see that b is a fun.

Now if you add this:

c = Object.create b
console.log b

b becomes an Object!

I don't really know what it could mean though...

igl commented 9 years ago

Why do you hate fun? I don't think fun is the problem. jquery-ui is probably doing an a instanceof A check and nothing will be instanceof A unless you use the A constructor to build object a and b instanceof Object is true.

I don't think there is a sufficient way to clone an object other than Object.create and still be pre es5 compatible.

haskellcamargo commented 9 years ago

The situation isn't that I hate fun. The situation is that this is a side-effect that shouldn't happen, as much as objects must be cloned, as says in the documentation. It is an instance of a closure which, in depth, is an object, but it's not the instance that was supposed to be. This error isn't so perceptible - and jQuery UI will not warn us about them. You'll stay in a problem caused by the language that shouldn't happen.