text: This document aims to cover the basic syntax and semantics of the Serpentine language. Although the syntax is compatible with that of the Python language, its semantics differ in a number of ways, mostly due to the constraints of the Dalvik virtual machine. This means that some programs will behave differently to the way they would run in a Python interpreter.
  We do not cover package building in any detail in this document. See the Getting Started document for a brief guide to building a package.
  As in Python, variables do not need to be declared. Values are simply assigned to names as they are needed:
  a = 123 b = float(4.0) c = long(4294967296) d = -1.1e64 text = "Hello" paint = Paint()
  Note the use of
  float and
  long built-in functions. The default type for
  integers is the 32-bit
  int type, and the default type for floating point
  numbers is the 64-bit
  double type. The
  int,
  float,
  long and
  double
  built-in functions can be used to cast values from one type to another.
  However, when specifying constants as in the above code, the functions are
  simply used to indicate that a constant should be encoded using a specific
  type - no method calls are generated in this case.
  Unlike Python, once a variable has been defined, its type is fixed. You cannot assign a value of a different type to it unless the value can be implicitly cast to the variable's type:
  a = 123 b = float(4.0) a = b # a = 4 (integer) d = long(4294967296) e = 1 f = d + e # f = 4294967297 (long)
  Implicit casting is only performed for primitive numeric types. This is useful when passing values of a certain type to standard Java or Android APIs that expect different, but compatible types.
  Instances of classes can be created in the usual way. The action of creating an instance associates its type with the variable it is assigned to, making it possible to call instance methods:
  view = TextView(self) view.setText("Hello world!")
  Python's built-in collection types - lists, dictionaries, tuples and sets - are
  represented in some form in Serpentine, but have different behaviours since
  they are based on the more restrictive Java types:
  ArrayList,
  HashMap and
  HashSet. For convenience, the Python notation used for lists, dictionaries,
  tuples and sets is supported by the compiler, but simply maps to these types.
  l = ["Hello", "World"] t = ("A", "B", "C") d = {"ABC": 123, "DEF", 456} s = {"alpha", "beta", "gamma"}
  Arrays are also supported in the language and can be created using the
  array
  built-in function. This takes two forms: a two argument version that allows an
  empty array to be created, and a one argument version that converts an existing
  collection to an array. The following two examples demonstrate these two forms:
  # Create an empty array with space for 4 integers. a = array(int, 4) # Create a string array from an existing string list. a = array(["The", "quick", "brown", "fox"])
  The basic control flow structures are available. These include
  if statements,
  while loops and
  for loops. There are some restrictions on what can be done
  in these structures that may be surprising to Python programmers.
  Here is an example
  if...
  elif...
  else structure that behaves the same way
  as it would when run in a Python interpreter:
  if i < 1: s = "Less than 1\n" elif i == 1: s = "Equals 1\n" else: s = "Greater than 1\n"
  One point worth making is that the string variable,
  s, is not defined before
  the structure, yet the intention in the above code is to make the variable
  available for use in later code in the same method. This can only be done if
  the variable is defined in all of the possible code paths through the
  structure. If not, the variable will be defined locally to the structure and
  cannot be accessed afterwards.
  The simplest type of loop is the
  while loop:
  s = "" i = 0 while i < 10: s += str(i) + " " i = i + 1 expected = "0 1 2 3 4 5 6 7 8 9 "
  The
  else clause from Python is also supported for
  while loops. The
  else
  clause is only executed if the loop is exited via its continuation condition.
  If the loop is exited via the
  break keyword, the
  else clause is skipped:
  s = "" i = 0 while i < 10: s += str(i) + " " if i == 5: break i = i + 1 else: s += str(i) expected = "0 1 2 3 4 5 "
  The variables used for the loop's condition must already be defined before they
  are used in the loop. The limitations on defining variables inside the loop
  that we had with the
  if statement also apply for
  while loops. New variables
  defined inside the loop are only accessible outside it if they are also defined
  in an
  else clause. The only exception with this is if the loop is
  unconditionally executed:
  while True: s = get_input() if s != "": break
  The other type of loop is the
  for loop. This is used to iterate over the
  contents of a collection:
  s = "" l = [0, 1, 2, 3, 4, 5] for i in l: s += str(i) + " "
  As well as lists, it is also possible to iterate over arrays, sets and tuples
  with a
  for loop. As with
  while loops,
  break statements can be used to
  exit the loop,
  continue statements cause execution to return to the start of
  the loop for the next iteration, and
  else clauses are executed if no
  break
  keyword is encountered.
  Classes are defined as in Python, but with some limitations and differences in how they are presented to the virtual machine. Unlike in Python, classes can only be derived from at most one base class:
  class HelloActivity(Activity): def __init__(self): Activity.__init__(self)
  Methods are defined in the same way as in Python. Where a method is a reimplementation of a method in a base class or interface, it can be defined without annotating it with a decorator:
  def onCreate(self, bundle): Activity.onCreate(self, bundle) view = TextView(self) view.setText("Hello world!") self.setContentView(view)
  Classes can be defined without a base class, in which case the result is an interface:
  class ValueInterface: @args(int, [int]) def getValue(self, x): pass
  Because the method is only defined here, a decorator is needed in order to
  define the return type and the method's argument types. The argument types are
  always defined in a list, even if there is only one of them. The
  self
  argument is never included in the list.
  Although classes can only inherit from one base class, they can implement
  multiple interfaces. These are declared with the
  __interfaces__ class
  attribute, which is a list of interface classes:
  class InterfacesActivity(TestActivity): __interfaces__ = [ValueInterface] # ... def getValue(self, x): return x * 2
  This indicates that the class provides implementation of the methods defined by
  the interfaces in the list. In the above example, the
  InterfacesActivity
  class is declaring that it implements the methods defined by the
  ValueInterface interface class defined earlier.
  Declaring that a class implements an interface enables instances of that class
  to guarantee that they provide implementations of certain methods without tying
  the implementation to that class or its subclasses. Another unrelated class can
  define the same interface and be used interchangeably with the class defined
  above in cases where it is only important that an object provides a
  getValue
  method with that particular signature.
  Classes can contain static methods that are invoked directly on a class instead
  of being invoked on an instance of it. These are defined in the same way as
  regular methods, except that they are annotated with the
  @static decorator as
  in the following example:
  class Other(Object): @static @args(String, [int]) def fn(i): return str(i)
  Note that we retain the convention used in Python for static methods, omitting
  the unnecessary
  self parameter that is defined in regular methods.
  Exceptions are generally used in the same way as in Python, with some
  limitations. The biggest omission is the lack of support for the
  finally
  keyword.