QuickSilver 0.5 – Class Vars, Inst Vars, Self, Super, etc

February 8, 2011

QuickSilver Version 0.5

QuickSilver Version 0.5

http://www.silversmalltalk.com/index3.html

Above is QuickSilver 0.5 running in a Safari browser. The latest source code is here.

Code in the demo above is:

1 to: 100 do:[:i |
Vm println: i + ' hello world!'].
nil

There are several enhancements in version 0.5.

  • self and super work properly
  • instance variables and class variables
  • proper metaclass hierarchy Object class superclass => Class
  • true and false map to True and False classes repectively

There are the beginnings of a class hierarchy for widgets with default class variables:

TestWindow open
==>
opens a window

TestWindow initHeight: 75.
TestWindow open
==>
opens a smaller window

Tomorrow I will add cascades and improvements to block statement generation including support for non-local returns.

Also, I will change the main page of the site to run QuickSilver and then we can start building some community support tools.

23 Responses to “QuickSilver 0.5 – Class Vars, Inst Vars, Self, Super, etc”

  1. Jose Says:

    Silver Smalltalk is Open source? GPL2?

  2. Jose Says:

    One mini bug?

    1 to: 100 do:[:i |
    Vm println: i + ‘ hello world!’.
    (each = 2) ifTrue:[^ each].
    ].
    nil

    Out must be

    1 hello world!
    2 hello world!

    (^ out form method that include the block)

    Please see fix on second example (solved with exception) of http://diegogomezdeck.blogspot.com/2006/07/st2js-traductor-de-smalltalk.html

  3. Peter Fisk Says:

    Thank you Jose.

    I have made a note of the bug and your blog page.

    — Peter

  4. Jose Says:

    Are you think on put your code on source repository (as google code)?

    issue tracking, svn, downloadable versions, wiki page,…

    GREAT WORK Peter!!

  5. Jose Says:

    Peter, previous link is not my blog (i found googling: “smalltalk javascript”).

    I like another (simple) solution witout exceptions…

    Smalltalk:

    1 to: 3 do:[:i |
    Vm println: i + ‘ hello world!’.
    (i=2) ifTrue:[^ i].
    ].

    Javascript:

    function() {
    for(var i=1;i use null to check if inner blocks returns something

  6. Jose Says:

    Peter let me fix my previous post…

    Javascript:

      function() {
        for(var i=1;i<=3;i++){
          if ((result1 = (function() {
            alert(i+(' hello world!'));
            if (i==2) {
              if ((result2 = (function() {
                return i;
                return null;
              })()) != null) return result2;
            }
            return null;
          })()) != null) return result1;
        }
      }
    

    1.- inner blocks (or anonymous js functions returns null at end).
    2.- parent functions check if inner anonymous functions returns something not null to propagate.

    note: if smalltalk inner blocks returns nill js compiler use Smalltalk.vars.nilObject => use null to check if inner blocks returns something

    • Peter Fisk Says:

      Jose,

      I pass a JavaScript object called _homeContext_. If any of the inner functions sets a return value in _homeContext_ it causes a return from the current block.

      Version 0.6 is available.

      Please see if you can find any cases where it fails.

      Thanks,

      — Peter

      • Jose Says:

        I found a bug… performWithArgs lose _homeContext_

        An example:

        Using ifTrue: method works fine,

        (1=1) ifTrue:[^3].
        ---
        function() {
        var _homeContext_={};
        return (((1)==(1)))?function(_homeContext_) {
        return _homeContext_.returnValue=(3);
        }(_homeContext_) : Smalltalk.vars.nilObject;
        if (_homeContext_ && _homeContext_.returnValue)return _homeContext_.returnValue;
        ;
        }
        ---
        3
        

        But using custom ‘if:then:’ fails (‘performWithArgs’ bug?),

        Object class if:(1=1) then:[^3].
        ---
        function() {
        var _homeContext_={};
        return (Smalltalk.vars.SystemDictionary.at('Object')).getClass().performWithArgs('if:then:',[((1)==(1)),function(_homeContext_) {
        return _homeContext_.returnValue=(3);
        },_homeContext_]);
        }
        ---
        nil
        

        Please note that:
        · ‘performWithArgs’ calls to ‘if:then:’ with three when only need two (ignoring the third: ‘_homeContext_’).
        · the check of ‘_homeContext_’ is inexistent in ‘performWithArgs’.

        The code of ‘if:then:’ is,

        Object class _compileMethod: '
        if: aBoolean then: aBlock
          ^ (aBoolean) ifTrue: aBlock'
        
      • Peter Fisk Says:

        Jose,

        I haven’t looked into custom control structures yet.
        They are certainly possible to implement.

        This should be deferred to release 1.1.

        — Peter

  7. Jose Says:

    I think that bug exist on every smalltalk method (called from ‘performWithArgs’) that use a Block as argument…

  8. Jose Says:

    Another approach, to avoid additional parameters, are a special return class (ReturnValue) to return values and check the existence of block return…

    Sorry for Java code, I extracted from an email that I sent to James Ladd (creator of Redline Smalltalk: Smalltalk on Java) => It’s simple translate it to Javascript code…

    public class ReturnValue {
    private Object value;

    public ReturnValue(Object valueToReturn) {
    this.value = valueToReturn;
    }

    public Object getValue() {
    return value();
    }
    }
    [/source]

    And return this class on block returns


    doReturn(value);

    [/source]

    Source code of doReturn:

    public ReturnValue doReturn(Object value) {
    if ( (value != null) && (value instanceof ReturnValue) ) {
    return (ReturnValue) value;
    }
    return new ReturnValue(value);
    }
    [/source]

    Then (all) internal Callers check the existence of return to propagate it

    object result = call(method, arguments);
    if (result != null && result instanceof ReturnValue) { doReturn(result) }
    [/source]

    And Parent (block creator) check the existence of return to return their real value

    object result = call(method, arguments);
    if (result != null && result instanceof ReturnValue) { return ((ReturnValue) result).value() }
    [/source]

    What do you think about this solution? It’s possible or see any inconvenient?

    • Peter Fisk Says:

      It may be better than the current solution.

      Maybe in release 1.1.

      — Peter

      • Jose Says:

        Peter, It’s not a bug on custom-control-structures, It’s a bug on any smalltalk method that received a Block as argument andis called from ‘performWithArgs’, you can duplicate this bug with this code:

        (5 range) do:[:i | (i=3) ifTrue: [^99]]

        when i is 3 breaks the loop an shows 99, but currently process all items on collection (0,1,2,3,4,5)

      • Peter Fisk Says:

        Jose,

        I tried this:

        10 range do:[:i |
        i = 3 ifTrue:[^i].
        Transcript println: i].
        ^nil

        and it worked fine.

        In your example, the range (0,1,2,3,4,5) will be returned at the end of loop execution regardless of where the loop exits. That is because the “do:” message returns the receiver when the loop finishes.

      • Jose Says:

        silversmalltalk code: please see Transcript before return…

          a:= {[1,2,3,4,5]}.
          a do: [:i|
              Transcript println: i.
              (i=3) ifTrue: [^ 99].
          ].
        

        Out:
        1
        2
        3
        4
        5

        Squeak code:

        #(1,2,3,4,5) do: [:i|
           Transcript show: (i asString).
           (i=3) ifTrue: [ ^ 99 ].
         ].
        

        Out:
        1
        2
        3

      • Jose Says:

        Please see:

          10 range do:[:i |
            (i = 3) ifTrue:[^i].
            Transcript println: i.
          ].
        

        Out: FINE (breaks on 3)

        0
        1
        2

          5 range do:[:i |
            Transcript println: i.
            (i = 3) ifTrue:[^i].
          ].
        

        Out: WRONG (iterate 5 times)

        0
        1
        2
        3
        4
        5

      • Peter Fisk Says:

        Ok, that looks like a bug when the condition is the last statement.

        I will add a “gen code” capability to the Vm class.
        It will produce the JavaScript code without compiling or executing it.

        Then we can look at the code to see what is happening.

        You are doing good work Jose.

        Thanks,

        — Peter

      • Peter Fisk Says:

        Hi Jose,

        The problem is fixed. There was a condition check missing in the generated code for looping statements (to:do:, whileTrue:, etc).

        Squeak:
        #(0 1 2 3 4 5) do:[:i |
        Transcript show: i;cr.
        (i = 3) ifTrue:[^i].
        ]

        shows 0,1,2,3 on the Transcript and returns 3

        QuickSilver:

        5 range do:[:i |
        Transcript println: i.
        (i = 3) ifTrue:[^i].
        ]

        shows 0,1,2,3 on the Transcript and returns 3

        same as Squeak.

        QuickSilver 0.83 is now in the repository.

        Thanks,

        — Peter

      • Jose Says:

        You’re as fast as ever… (is a pleasure)

  9. Jose Says:

    Sorry, I fix my previous post:

    Another approach, to avoid additional parameters, are a special return class (ReturnValue) to return values and check the existence of block return…

    Sorry for Java code, I extracted from an email that I sent to James Ladd (creator of Redline Smalltalk: Smalltalk on Java) => It’s simple translate it to Javascript code…

    public class ReturnValue {
      private Object value;
    
      public ReturnValue(Object valueToReturn) {
        this.value = valueToReturn;
      }
     
      public Object getValue() {
        return value();
      }
    }
    

    And return this class on block returns

    ...
    doReturn(value);
    ...
    

    Source code of doReturn:

    public ReturnValue doReturn(Object value) {
      if ( (value != null) && (value instanceof ReturnValue) ) {
        return (ReturnValue) value;
      }
      return new ReturnValue(value);
    }
    

    Then (all) internal Callers check the existence of return to propagate it

    object result = call(method, arguments);
    if (result != null && result instanceof ReturnValue) { doReturn(result) }
    

    And Parent (block creator) check the existence of return to return their real value

    object result = call(method, arguments);
    if (result != null && result instanceof ReturnValue) { return ((ReturnValue) result).value() }
    

    What do you think about this solution? It’s possible or see any inconvenient?


Leave a reply to Peter Fisk Cancel reply