Create JS Object in Smalltalk

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

Create JS Object in Smalltalk

Sean P. DeNigris
Administrator
How do I rewrite the {...} part of the following in Amber?

$("#MySplitter").splitter({
                splitVertical: true,
                sizeLeft: true
        });

I naively tried:
    '#MySplitter' asJQuery splitter: { 'splitVertical' -> true. 'sizeLeft' -> true }
but that didn't seem to work...
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Herby Vojčík


Sean P. DeNigris wrote:

> How do I rewrite the {...} part of the following in Amber?
>
> $("#MySplitter").splitter({
> splitVertical: true,
> sizeLeft: true
> });
>
> I naively tried:
>      '#MySplitter' asJQuery splitter: { 'splitVertical' ->  true. 'sizeLeft'
> ->  true }

It's not naive, Amber has syntax for this, you just must start it with #{ instead of {.
{'foo'->'bar'. 'baz'->'quux'} is of course a legal, though different, thing -- an array with two associations (it would be worse if it magically transformed to something else just because all of it's elements are associations -- dynamic array stays dynamic array, for creating 'hash' there is different syntax).

It needs to be mentioned, though, that #{...} syntax does not create plain objects,
but HashedCollection instances, OTOH, for 99% of cases or more they can be used
in place where inline object are used in JS (for example, various jQuery api calls).

--
You received this message because you are subscribed to the Google Groups "amber-lang" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Sean P. DeNigris
Administrator
Herby Vojčík wrote
#{...} syntax does not create plain objects,
but HashedCollection instances, OTOH, for 99% of cases or more they can be used
in place where inline object are used in JS (for example, various jQuery api calls).
Thanks! That worked. I added an explanation to the wiki (https://github.com/amber-smalltalk/amber/wiki/From-smalltalk-to-javascript-and-back#creating-objects). Let me know if it's clear:

##JavaScript Objects from Smalltalk
...
###Creating Objects

Sometimes you need to create an inline JS object, for example as an argument to this splitter() function:

$("#MySplitter").splitter({
    splitVertical: true,
    sizeLeft: true
});

In 99% of these cases, you can simulate the object with a HashedCollection like so: { 'splitVertical' -> true. 'sizeLeft' -> true }
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Herby Vojčík
In reply to this post by Sean P. DeNigris


"Sean P. DeNigris" <[hidden email]>napísal/a:

I added an explanation to the wiki
(https://github.com/amber-smalltalk/amber/wiki/From-smalltalk-to-javascript-and-back#creating-objects).
Let me know if it's clear:

##JavaScript Objects from Smalltalk
...
###Creating Objects

Sometimes you need to create an inline JS object, for example as an argument
to this splitter() function:

$("#MySplitter").splitter({
    splitVertical: true,
    sizeLeft: true
});

In 99% of these cases, you can simulate the object with a HashedCollection
like so: { 'splitVertical' -> true. 'sizeLeft' -> true }

Well, all fine, except the missing # at the beginning. I would include the complete call, to see whole JS and whole ST.


--
You received this message because you are subscribed to the Google Groups "amber-lang" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Sean P. DeNigris
Administrator
Herby Vojčík wrote
missing # at the beginning
Ha ha, I left it out again. Thanks for fixing the wiki.
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Sean P. DeNigris
Administrator
In reply to this post by Herby Vojčík
Herby Vojčík wrote
In 99% of these cases, you can simulate the object with a HashedCollection
like so: { 'splitVertical' -> true. 'sizeLeft' -> true }
In my current project, I tried to port:
  $('#jstree').jstree({
    "plugins" : [ "contextmenu" ]
  });
as:
  '#navigation' asJQuery jstree: #{ 'plugins' -> { 'contextmenu' } }.
which did not work. There was no error, it just didn't properly initialize the jsTree.

I then found http://stackoverflow.com/a/13668585/424245 and ended up with:
        options :=  self jsObject.
        options at: #plugins put: { 'contextmenu' }.
        '#navigation' asJQuery jstree: options.
where:
    MyClass>>jsObject
        <return {}>
which worked.

Did I find the 1% case?
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Herby Vojčík
Interesting, as there is nothing special with this case on the first look. It's probably something with JSTree treating plugins array somehow strangely. Yes, these cases make that 1%.

BTW, when I really need an empty JS object, I am too lazy to create special method for it. I do `JSON parse: '{}'` ;-)

Herby

Sean P. DeNigris wrote:

> Herby Vojčík wrote
>> In 99% of these cases, you can simulate the object with a HashedCollection
>> like so: { 'splitVertical' ->  true. 'sizeLeft' ->  true }
>
> In my current project, I tried to port:
>    $('#jstree').jstree({
>      "plugins" : [ "contextmenu" ]
>    });
> as:
>    '#navigation' asJQuery jstree: #{ 'plugins' ->  { 'contextmenu' } }.
> which did not work. There was no error, it just didn't properly initialize
> the jsTree.
>
> I then found http://stackoverflow.com/a/13668585/424245 and ended up with:
> options :=  self jsObject.
> options at: #plugins put: { 'contextmenu' }.
> '#navigation' asJQuery jstree: options.
> w
here:

>      MyClass>>jsObject
> <return {}>
> which worked.
>
> Did I find the 1% case?
>
>
>
> -----
> Cheers,
> Sean
> --
> View this message in context: http://forum.world.st/Create-JS-Object-in-Smalltalk-tp4769429p4771047.html
> Sent from the Amber Smalltalk mailing list archive at Nabble.com.
>

--
You received this message because you are subscribed to the Google Groups "amber-lang" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Sean P. DeNigris
Administrator
There is something very odd going on.

Here's a snippet from my method:
install
       
        | action menuItem |
        action := self jsObject
                at: 'action' put: [ :node | console log: 'do it. do it' ];
                yourself.
        menuItem := self jsObject
                at: 'create' put: action;
                yourself.

The compiled JS is:
fn: function (){
var self=this;
var options,action,menuItem,items;
...
return smalltalk.withContext(function($ctx1) {
var $1,$2,$3,$4,$5,$6,$7;
...
$2=self._jsObject();
$ctx1.sendIdx["jsObject"]=1;
_st($2)._at_put_("action",(function(node){
return smalltalk.withContext(function($ctx2) {
return _st(console)._log_("do it. do it");
}, function($ctx2) {$ctx2.fillBlock({node:node},$ctx1,1)})}));
$ctx1.sendIdx["at:put:"]=1;
$3=_st($2)._yourself();
$ctx1.sendIdx["yourself"]=1;
action=$3;
$4=self._jsObject();
$ctx1.sendIdx["jsObject"]=2;
_st($4)._at_put_("create",action);
$ctx1.sendIdx["at:put:"]=2;
$5=_st($4)._yourself();
menuItem=$5;

The interesting part is:
$3=_st($2)._yourself();
action=$3;
$5=_st($4)._yourself();
menuItem=$5;

In the first case, the send to #yourself is effectively throw away, where in the second, its result is used. And indeed, if I hand edit from `menuItem=$5;` to `menuItem=$4;`, the code acts as expected.

Is this a known bug? I briefly scanned the compiler code and I'm willing to take a crack at it given a pointer in the right direction.
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Herby Vojčík


Sean P. DeNigris wrote:

> There is something very odd going on.
>
> Here's a snippet from my method:
> install
>
> | action menuItem |
> action := self jsObject
> at: 'action' put: [ :node | console log: 'do it. do it' ];
> yourself.
> menuItem := self jsObject
> at: 'create' put: action;
> yourself.
>
> The compiled JS is:
> fn: function (){
> var self=this;
> var options,action,menuItem,items;
> ...
> return smalltalk.withContext(function($ctx1) {
> var $1,$2,$3,$4,$5,$6,$7;
> ...
> $2=self._jsObject();
> $ctx1.sendIdx["jsObject"]=1;
> _st($2)._at_put_("action",(function(node){
> return smalltalk.withContext(function($ctx2) {
> return _st(console)._log_("do it. do it");
> }, function($ctx2) {$ctx2.fillBlock({node:node},$ctx1,1)})}));
> $ctx1.sendIdx["at:put:"]=1;
> $3=_st($2)._yourself();
> $ctx1.sendIdx["yourself"]=1;
> action=$3;
> $4=self._jsObject();
> $ctx1.sendIdx["jsObject"]=2;
> _st($4)._at_put_("create",action);
> $ctx1.sendIdx["at:put:"]=2;
> $5=_st
($4)._yourself();

> menuItem=$5;
>
> The interesting part is:
> $3=_st($2)._yourself();
> action=$3;
> $5=_st($4)._yourself();
> menuItem=$5;
>
> In the first case, the send to #yourself is effectively throw away, where in
> the second, its result is used. And indeed, if I hand edit from
I don't understand, what throwaway? In both cases, result of call to ._yourself() is used ($3 is first case, $5 in second case).

> `menuItem=$5;` to `menuItem=$4;`, the code acts as expected.

Well, yourself. If you send yourself to JS object, you don't get that JS object (unboxed), but JSObjectProxy instance (boxed). It's the same for any other value which is boxed / unboxed (numbers, strings), though here it is the extreme case, changing actual object to its wrapper.

But that's how yourself works - it returns the ST receiver, and in case of JS objects that need wrapping in JSObjectProxy class, it is, alas, the JSObjectProxy instance.

You may argue that yourself should return the JS objec
t itself, if there would be agreement on that, JSObjectProxy >> yourself can be added.

> Is this a known bug? I briefly scanned the compiler code and I'm willing to
> take a crack at it given a pointer in the right direction.

Again, is there a bug or you just misread $3 as $2 in "action = $3"?

> -----
> Cheers,
> Sean
> --

Herby

--
You received this message because you are subscribed to the Google Groups "amber-lang" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Sean P. DeNigris
Administrator
Herby Vojčík wrote
I don't understand, what throwaway? In both cases, result of call to ._yourself() is used ($3 is first case, $5 in second case).
Okay, I could've sworn is was $2, but I recompiled subsequently and can't go back and check, so let's just chock it up to a misread.

But...
Herby Vojčík wrote
If you send yourself to JS object, you don't get that JS object (unboxed)
That explains why the yourself version doesn't work, but I'm still confused as to why the following pattern works:
        items := self jsObject. "#1"
        items at: 'items' put: [ :arg | menuItem ]. "#2"
        options := self jsObject. "#3"
        options at: 'contextmenu' put: items. "#4"
        options at: 'plugins' put: { 'contextmenu' }. "#5"
        '#navigation' asJQuery jstree: options. "#6"
where:
    MyClass>>jsObject
        <return {}>

In lines #1 & #3, aren't I storing the same boxed proxy that would be returned by #yourself? Then in lines #4 and #6, aren't I passing the proxy again? But this time it all works...

If I instead us the following pattern, it works, but for more obvious reasons (to me):
        menuItem := self jsObject
                at: 'create' put: itemOptions;
                jsObject.
        items := self jsObject
                at: 'items' put: [ :arg | menuItem ];
                jsObject.
Now I'm explicitly storing and passing around the underlying JS objects. How can this be equivalent to the first example code above?

Thanks for walking me through this!
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Herby Vojčík


Sean P. DeNigris wrote:
 > Herby Vojčík wrote
 >> I don't understand, what throwaway? In both cases, result of call to
 >> ._yourself() is used ($3 is first case, $5 in second case).
 >
 > Okay, I could've sworn is was $2, but I recompiled subsequently and
can't go
 > back and check, so let's just chock it up to a misread.
 >
 > But...
 >
 > Herby Vojčík wrote
 >> If you send yourself to JS object, you don't get that JS object
(unboxed)
 >
 > That explains why the yourself version doesn't work, but I'm still
confused
 > as to why the following pattern works:
 > items := self jsObject. "#1"
 > items at: 'items' put: [ :arg | menuItem ]. "#2"
 > options := self jsObject. "#3"
 > options at: 'contextmenu' put: items. "#4"
 > options at: 'plugins' put: { 'contextmenu' }. "#5"
 > '#navigation' asJQuery jstree: options. "#6"
 > where:
 >      MyClass>>jsObject
 >          <return {}>
 >
 > In lines #1&  #3, aren't I storing the same boxed proxy that would be
 > returned by #yourself? Then in lines #4 and #6, aren't I passing the
proxy

No. The boxing of foo only occurs when foo needs to act as a receiver
(receiver _must_ be a Smalltalk object). So, return value of `self
jsObject` is indeed that JS object, unboxed. OTOH, if you send #yourself
to it, it is  boxed not because of yourself, but because of being a
receiver.

 > again? But this time it all works...
 >
 > If I instead us the following pattern, it works, but for more obvious
 > reasons (to me):
 > menuItem := self jsObject
 > at: 'create' put: itemOptions;
 > jsObject.
 > items := self jsObject
 > at: 'items' put: [ :arg | menuItem ];
 > jsObject.

Yes, this works, since you ask boxed JSObjectProxy for its wrapped
jsObject (by sending it #jsObject). But that code is, as you surely see,
wrong from design reasons, as it's assuming the proxying, which should
be transparent from ST code view.

As I wrote, one possibility is to come to the conclusion the
JSObjectProxy >> yourself should be `^ self jsObject`, which would make
the general pattern work well, but there is a consistency problem with
the rest of yourselfs, which always return boxed object.

In the present state of things, #value is the message that returns
unboxed receiver, but it has its own semantic for BlockClosure, so maybe
Nico should allow to introduce special receiver for getting the unboxed
value.

 > Now I'm explicitly storing and passing around the underlying JS
objects. How
 > can this be equivalent to the first example code above?
 >
 > Thanks for walking me through this!
 > -----
 > Cheers,
 > Sean
 > --

Herby

--
You received this message because you are subscribed to the Google Groups "amber-lang" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Sean P. DeNigris
Administrator
Herby Vojčík wrote
The boxing of foo only occurs when foo needs to act as a receiver
Oh, I see now. This is a trap for new users. I think it should be clearly explained somewhere prominent.

Herby Vojčík wrote
As I wrote, one possibility is to come to the conclusion the
JSObjectProxy >> yourself should be `^ self jsObject`X
If the purpose of the proxy is to temporarily wrap the jsObject to send ST messages to it, maybe all its methods should return the jsObject. Then it will be wrapped again if you need to send message to it, right? It may be less efficient, but the current state is confusing - sometimes you get a jsObject, and sometimes a proxy...
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Sean P. DeNigris
Administrator
In reply to this post by Herby Vojčík
Herby Vojčík wrote
But that code is, as you surely see,
wrong from design reasons, as it's assuming the proxying, which should
be transparent from ST code view.
It's just a symptom of the underlying problem. The pattern of requiring:
tmp := self jsObject.
jsObject doSomething.
vs.
tmp := self jsObject
    doSomething;
    yourself.
makes it just as obvious that something unusual is going on as sending #jsObject
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Herby Vojčík


Sean P. DeNigris wrote:

> Herby Vojčík wrote
>> But that code is, as you surely see,
>> wrong from design reasons, as it's assuming the proxying, which should
>> be transparent from ST code view.
>
> It's just a symptom of the underlying problem. The pattern of requiring:
> tmp := self jsObject.
> jsObject doSomething.
> vs.
> tmp := self jsObject
>      doSomething;
>      yourself.
> makes it just as obvious that something unusual is going on as sending
> #jsObject

Yes, of course. I am beginning to think yourself should always return
unboxed receiver (and special receiver should be dedicated to get boxed
one).

> -----
> Cheers,
> Sean
> --

Herby

--
You received this message because you are subscribed to the Google Groups "amber-lang" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Herby Vojčík


Herby Vojčík wrote:

>
>
> Sean P. DeNigris wrote:
>> Herby Vojčík wrote
>>> But that code is, as you surely see,
>>> wrong from design reasons, as it's assuming the proxying, which should
>>> be transparent from ST code view.
>>
>> It's just a symptom of the underlying problem. The pattern of requiring:
>> tmp := self jsObject.
>> jsObject doSomething.
>> vs.
>> tmp := self jsObject
>> doSomething;
>> yourself.
>> makes it just as obvious that something unusual is going on as sending
>> #jsObject
>
> Yes, of course. I am beginning to think yourself should always return
> unboxed receiver (and special receiver should be dedicated to get boxed
eh, I meant special message. Like, #asReceiver or #asSmalltalkObject.
> one).
>
>> -----
>> Cheers,
>> Sean
>> --
>
> Herby
>

--
You received this message because you are subscribed to the Google Groups "amber-lang" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

sebastianconcept
In reply to this post by Sean P. DeNigris
or with # instead?

'plugins' -> #{ 'contextmenu' }

sebastian

o/

> On 30/07/2014, at 19:32, "Sean P. DeNigris" <[hidden email]> wrote:
>
> 'plugins' -> { 'contextmenu' }

--
You received this message because you are subscribed to the Google Groups "amber-lang" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Create JS Object in Smalltalk

Sean P. DeNigris
Administrator
sebastianconcept wrote
or with # instead?
'plugins' -> #{ 'contextmenu' }
No it actually expects an array. I tried unsuccessfully with # first.
Cheers,
Sean