|
Language
Migration from Python
EcmaScript
Equivalents for those migrating from Python
This document is an introduction to the JavaScript
language (aka EcmaScript AKA ScriptEase) for those who
are already familiar with the Python scripting language.
Python and JavaScript are very similar languages: they
both closely follow most of the syntax and control flow
of the 'C' programming language, they both extend that
syntax into an object-oriented and extensible script
language, and they both are designed to be embedded
within C/C++/Java applications as an extension or command
language for that application. In most cases the differences
are only in terminology.
Because the languages are so similar, this document
will be brief. It will cover only those areas where
a Python script writer may have difficulty finding the
equivalent capability in JavaScript. (If you are a Python
user, moving to JavaScript, and have issues that you
think should be added to this document then please visit
http://support.nombas.com/
Please do not send Dr. Scripter flames about "why
my embedded script language is so much better than yours!!!"--the
Doctor is only interested in helping, and is not interested
in entering into holy language wars)
---------- Revision History for this document --------------
Mar 11 2003 - Initial document
------------------------------------------------------------
Topics
dictionaries
A Python "dictionary" is an unordered set
of key:value pairs. The equivalent concept in
JavaScript is the "associative array" or,
more simply, the Object. The syntax for using a Python
dictionary is part of the standard behavior for a JavaScript
Object (and all objects which inherit from Object, i.e.
all objects).
Python code:
emp = { 'name':'john', 'sal':50000 }
emp['food'] = 'pie'
JavaScript equivalent code:
emp = { 'name':'john', 'sal':50000 }
emp['food'] = 'pie'
or
emp = { name:'john', sal:50000 }
emp.food = 'pie' // note that emp.food==emp['food']
other common Python dictionary syntax involves keys()
to enumerate, del to delete, and has_key()
to determine if a key exists, as demonstrated in this
code
Python code:
emp = { 'name':'john', 'sal':50000, 'food':'pie' }
del emp['sal']
k = emp.keys() # k = ['name', 'food' ]
h = emp.has_key('sal') # h = 0
JavaScript equivalent code
emp = { 'name':'john', 'sal':50000, 'food':'pie' }
delete emp[sal] // or delete emp.sal
for ( m in emp ) // for(...in...) enumerates members
k = m; // k='name' then k='food'
h = 'sal' in emp // h = false
In Python a key can be any immutable data, which including
tuples. Using a tuple as a key
does not have a direct JavaScript equivalent, although
it would be very close to use the toString() or toSource()
method on the JavaScript Array (similar to tuple) to
represent the member name (i.e. key).
lists
A Python list is equivalent to a JavaScript
Array object. The syntax for initializing them
can even be the same, e.g.:
Python code:
a = [ 'blue', 42, [1,2,3], 'dog' ]
b = a[1] # b = 42
c = a[2][1] # c = 2
l = len(a) # l = 4
l = len(l[2]) # l = 3
JavaScript equivalent code
a = [ 'blue', 42, [1,2,3], 'dog' ]
b = a[1] # b = 42
c = a[2][1] # c = 2
l = a.length // l = 4
l = l[2].length // l = 3
Except for the difference in determining length (a
Python len() function vs a JavaScript Array property),
these scripts are identical, including nesting of lists
within lists (Arrays within Arrays).
Python lists differ from JavaScript Arrays in that
operations on lists (e.g. replace, remove, insert) are
part of the Python language syntax (e.g., a[0:2]), whereas
the same operations on Arrays are instance methods of
the Array object (e.g. a.slice(), a.join(), etc...)).
(This difference goes along with a standard design philosophy
behind EcmaScript that instead of adding language syntax
or more data types, it is preferable to extend the capabilities
through defining new object types and methods, and inheriting
from those.)
Functionally, the capabilities of Python lists and
JavaScript Arrays are equivalent--the difference being
that a slice of a list is part of the Python language
syntax, but a slice of an array is a method of that
array. (Note: with the ScriptEase capabilities of making
all operators on objects dynamic, and operator overloading
on those objects, it would be possible to implement
the python-like a[1:2]=[blah] syntax, but that would
probably be confusing to someone with a pure-javascript
background who later came across the unfamiliar-looking
script.)
tuples
A Python tuple is just like a Python list
except that the elements of a tuple are immutable. Python
tuples also differ from lists in that tuples are initialized
with the parenthesis instead of square brackets. i.e.
Python code:
a = [ 'blue', 42, 'dog' ] # a is a list
b = ( 'blue', 42, 'dog' ) # b is a tuple
There
is no inherent language feature of JavaScript that maps
directly to a tuple. The most direct JavaScript equivalent
of a tuple would be an Array where each member of that
array has its DONTDELETE and READONLY attributes set.
There could be many ways to accomplish the creation
of a tuple with ScriptEase, most of which would involve
creating an array and applying the DONTDELETE and READONLY
attributes to each element (the other option would be
to disable the put callback after the array has been
created).
One interesting approach, done through the script language
itself, would be to add a tuple() method to instances
of the Array object, so that after an array was created
it could then be turned into a tuple. Here's an example
of what the script may look like:
function Array.prototype.tuple()
{
// for each element in this, apply readonly and dontdelete
for ( var i = 0; i < this.length; i++ )
setAttributes(this[i],DONT_DELETE | READ_ONLY );
}
The above approach could be applied in a javascript
script such as this:
JavaScript code
a = [ 'blue', 42, 'dog' ] // a is an Array
b = [ 'blue', 42, 'dog' ].tuple() // b is a tuple
The approach I would prefer, if you really want the
concept of a tuple in the language, would just be to
create a tuple() function that would take all of its
arguments and put them into an array while making each
member dont_delete and disabling further put() functions
so that no members can be added or changed. The C code
for such a tuple() method, using the ScriptEase ISDK/C,
would look like this:
C code for implementing the tuple() functions
// create callbacks so that no put can happen to a tuple
sebool JSE_CFUNC FAR_CALL tuple_put(secontext se,sestring prop)
{
// do nothing; do not allow any puts to this object
return True;
}
struct seObjectCallbacks tuple_callbacks =
{ NULL, tuple_put, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
// this C code is called from script calling tuple(parm1,parm2,parm3,...)
SE_CALLBACK(void) tuple(secontext se, sememcount argc)
{
seobject ret;
sememcount i;
// create an array object
ret = seMakeObject(se);
seSetArray(se,ret,0); // shortcut to calling the Array constructor
// for each argument to this function, set dontdelete element of array object
for ( i = 0; i < argc; i++ )
{
seAssign( se, ret,SE_NUM(i), SE_ARGS,SE_INDEX(i) );
seSetAttribs( se, ret,SE_NUM(i), SE_READONLY|SE_DONTDELETE );
}
// set the do-nothing put function so no additions can be made
seSetCallbacks(se, ret,SE_VALUE, &tuple_callbacks);
// return our new object from this function
sePutObject(se,SE_RETURN,SE_VALUE,ret);
}
With this tuple() method now added, the following JavaScript
will show the difference between making a tuple and
a plain Array.
JavaScript code
a = [ 'blue', 42, 'dog' ] // a is an Array
b = tuple( 'blue', 42, 'dog' ) // b is a tuple
(Should we provide a better version of tuple? A complete
tuple class or a better version of the above tuple wrapper
function? Maybe we're missing some need. If you have
ideas on this then please tell http://support.nombas.com/)
gotchas
In moving from Python to JavaScript, these are a few
items to watch out for:
- default global variables - According to the
EcmaScript specification, a variable that is not labeled
within a method with the var keyword is automatically
assumed to be a global variable. This can often lead
to problems when two methods both use the same variable
name (such as if one method looping through i
calls another method looping through its own i
variable, with neither declaring var i.
With the ScriptEase ISDK there are a couple of ways
to ease around this problem. The first is to use the
SE_OPT_DEFAULTLOCAL flag in the seContextParam seOptions
field. SE_OPT_DEFAULTLOCAL reverses the EcmaScript
standard so that variables not declared globally are
assumed to be local variables. The other option is
to use the SE_OPT_REQUIREVAR flag instead (although
both flags may be used together). SE_OPT_REQUIREVAR
tells the engine to create an error whenever it encounters
a variable that has not been declared with the var
keyword, and so if any variable is used without declaring
it first an exception will be generated specifying
the error, variable, script, and line number. We prefer
the SE_OPT_REQUIREVAR flag because 1) the default-local-var
option is non-standard and so may lead your users
to be confused when reading standards-compliant scripts,
and 2) the SE_OPT_REQUIREVAR flag has the added benefit
of helping to catch typographical errors such as using
a variable Count when it was declared as count.
If you have comments about this document, or what should
be added to this document, write to http://support.nombas.com/.
|