Function questions

45 views
Skip to first unread message

Bruce Sherwood

unread,
Dec 21, 2014, 7:51:50 PM12/21/14
to rapyd...@googlegroups.com
I'm confused about the RapydScript documentation concerning "Optional Arguments", "Variable number of arguments (*args)", and "Keyword Arguments (**kwargs)". For example, the documentation says that in classic Python the following will work, but that to make it work in RapydScript one must prepend the decoration "@kwargs". But in classic Python the following code gives the error TypeError: test() got multiple values for keyword argument 'foo'.

def test(foo, bar, kw):
    print(foo)  # 'baz'
    print(bar)  # 99
    print(kw)   # {foo: 1. bar: 3}
    print(kw.foo)   # 1

test('baz', foo=1, 99, bar=3)

Another thing: the following works in classic Python but not in 
RapydScript, with or without the @kwargs decoration:


def f(a=10, b=20, c=30):
    print(a, b, c) # classic gives 5 7 6; RS gives Object 20 30

f(a=5, c=6, b=7)

I'm left puzzled as how to think about the differences in handling
function calls in classic Python and RapydScript. Can someone
illuminate me? Thanks.




Bruce Sherwood

unread,
Dec 21, 2014, 11:24:39 PM12/21/14
to rapyd...@googlegroups.com
I made a mistake on the second example. Adding @kwargs does indeed work as expected.

How about the following?

class test:
    def __init__(self, a=100, b=200, c=300):
        print(a, b, c)

test(5, 6, 7) # this works

But test(a=5, b=6, c=7) does not work, nor does it work if I write the class like this:

class test:
    @kwargs
    def __init__(self, a=100, b=200, c=300):
        print(a, b, c)

Alexander Tsepkov

unread,
Dec 22, 2014, 10:51:41 AM12/22/14
to Bruce Sherwood, RapydScript
As far as the first example you mention, sounds like the error is in the documentation regarding expected Python behavior rather than in RapydScript logic itself. RapydScript overwrites shadows the duplicate argument, Python complains.

As for the second post, when you omit @kwargs, test(a=5, b=6, c=7) will not unpack the arguments into a, b, and c, that is correct behavior for the compiler, the error is in your code. You can still access them as kw.a if you include kw argument.

For your third example, you did stumble into a compiler error, which I wasn't aware of, if you look at what the code compiles to, the bug is obvious:

    function test(a, b, c){
        var self = this;
        if (typeof a === "undefined") a = 100;
        if (typeof b === "undefined") b = 200;
        if (typeof c === "undefined") c = 300;
        _$rapyd$_print(a, b, c);
    };
    test.prototype.__init__ = kwargs(test.prototype.__init__);

This will only affect the __init__ method, since it's a fake method that gets replaced in JavaScript. Other methods are not susceptible to this bug. I'm not sure if I can fix this without introducing other issues. If I replace the last line to override the function/constructor itself, it could break isinstance() and inheritance. I will do some testing with this later.

Bruce Sherwood

unread,
Dec 22, 2014, 4:40:46 PM12/22/14
to rapyd...@googlegroups.com, bruce.s...@gmail.com
Thanks, Alexander.

I should comment that it's quite a thrill to be able to write and run VPython programs in a browser. It's relatively easy to write a program that will run either in classic mode, with classic Python, but that will also run in a browser. Obviously the key element is RapydScript, but I also do quite a lot of preprocessing before handing the source to RapydScript. For example, VPython code can be written in synchronous mode, with infinite animation loops, which requires placing a flag in key places to permit Streamline to convert the code to an asynchronous structure.

Alexander Tsepkov

unread,
Dec 29, 2014, 7:12:58 PM12/29/14
to Bruce Sherwood, RapydScript
I've been playing with the compiler over the last few days trying to address this bug. Replacing the __init__ part with the constructor was easy, the problem is that kwargs doesn't work as expected on class methods. Upon further investigation I realized that this is because of the way it triggers the function call from within the decorator, effectively discarding the object that the function should be applied to.

Basically, the culprit is this guy in kwargs function definition: f.apply(f, args). There were some other minor bugs with kwargs, which I've fixed as well. I've also improved the tests for kwargs to test class methods. There is only one bug remaining, which I can't seem to figure out and the workaround is relatively easy, so I gave up on it for now. Basically, the following call seems to lose its arguments:

test = KeywordArgsTest(a=1, b=2)

Yet adding a fake positional argument (which will get overridden by a/b) fixes the issue. This also only seems to be the case with the constructor, and not other methods, and only when function is called via 'new' operator in JS. However, I'm not seeing this issue outside of the test, with the following example I tried:

function c() {
console.log(arguments);
}

c({a: 1}); // works fine
new c({a: 1}) // works fine, yet this same logic loses its arguments in the test - the breakage occurs prior to kwargs call, my constructor is now separated from the class-defining function, so it doesn't look like kwargs is at fault here

If someone can figure out what's going on with the test, I'd love to hear it. Otherwise, the logic is usable as is if you don't mind the 'fake' arg when using it in the constructor.


Reply all
Reply to author
Forward
0 new messages