Rotating Cube in JavaScript

November 25, 2008

My CSS-Parrot gave me an appetite for more in-browser graphics. This, led to my newest creation: A rotating “3D” cube, written with JavaScript.

Check it out here: http://kanelynchsucks.com/sfsr/rot_cube.html

(glory to Tzahi for hosting it)

Edit: The page is currently unavailible. If you’re interested, email me and I’ll send you a copy.

Please note, this cube is not really 3D.  I just hacked it together using a couple of tricks, which I think are rather clever.

My next post (or more) will explain thoroughly how I made the cube and the tricks that I used. But I highly recommend you, the readers of this blog, to try and figure it out yourself. It can be a fun exercise. The actual code is very readable, and the only mystery is – how did I do it?


Pickling Python Expressions

November 12, 2008

My last post introduced the concept of X, a class which “absorbs” operations and behaves like a function.
As many people pointed out, this was merely a syntactic alternative to lambda. You may like it, you may not.
Now, after a rewrite, X can now be pickled. But let me explain first.

Python lambdas cannot be pickled. In fact, python code cannot be pickled.
Pickling an object, aka serializing, is converting the object’s state (that is, its data) to a string, which can at a later time be unpickled to re-create the object with that state. The unpickling process instanciates that class, assuming it has not changed, and updating the new instance’s state to the pickled one. Python code is never stored.

Trying to pickle a class or a function might appear to work, but it does not really pickle it; it simply pickles the reference to it (and its state). Unpickling the string in a new terminal would prove that (as would a quick analysis of resulting string).

Attempts to pickle methods, nested functions or lambdas fail on the spot. That is because a reference to them cannot be kept (Actually, it can be. But they are rather volatile, so it might not be wise). Eventually, python code, or even expressions, cannot be pickled.

This brings me back to X. X allows you to do just that:

>>> expr = 1 + (X + 3) * 4
>>> s = pickle.dumps(expr)

(destory objects, change objects, switch an interpreter, whatever you wish)

>>> expr2 = pickle.loads(s)
>>> expr2(5)
33

By using X, the programmer can blend dynamic code with his data, and still be able to pickle it.
I believe this removes a very big limitation.

Just to be fair, I will note that there is another way to achieve this: Keep your expressions in a string, and eval it when you need it run. I highly recommend not doing it.

X’s new source code (a bit cryptic, but it’s the best I could do. Suggestions for simplification are welcomed) :

"""
x.py

Author: Erez Sh.
Date  : 11/11/2008
"""

import operator

def identity(x):
	return x

class _Return(object):
	"Pickle-able!"
	def __init__(self, value):
		self._value = value

	def __call__(self, *args):
		return self._value

class _Partial(object):
	"Pickle-able!"
	def __init__(self, callable, *args):
		self._callable = callable
		self._args = args

	def __call__(self, *args, **kwargs):
		args = self._args + args
		return self._callable(*args)

class _X(object):
	def __init__(self, func, *args_to_run):
		self.__func = func
		self.__args_to_run = tuple(args_to_run)

	def __getstate__(self):
		return self.__func, self.__args_to_run
	def __setstate__(self, state):
		self.__func, self.__args_to_run = state
	def __reduce__(self):
		#raise Exception("Deprecated!")
		return object.__reduce__(self)

	def __apply_un_func(self, func ):
		return _X(func, _Partial(self))
	def __apply_bin_func(self, func, arg ):
		return _X(func, _Partial(self), _Return(arg))
	def __apply_rbin_func(self, func, arg ):
		return _X(func, _Return(arg), _Partial(self))
	def __apply_multargs_func(self, func, *args ):
		return _X(func, _Partial(self), *map(_Return,args))

	def __call__(self, arg):
		return self.__func(*[x(arg) for x in self.__args_to_run])

	def __getattr__(self, attr):
		return self.__apply_bin_func( getattr, attr )

	def call(self, *args, **kwargs):
		return self.__apply_multargs_func( apply, args, kwargs)

	# Containers
	def __getitem__(self, other):
		return self.__apply_bin_func( operator.getitem, other )
	def __getslice__(self, a,b=None,c=None):
		return self.__apply_bin_func( operator.getslice, other )
	def in_(self, other):
		return self.__apply_bin_func( operator.contains, other )

	# Arith
	def __add__(self, other):
		return self.__apply_bin_func( operator.add, other )
	def __sub__(self, other):
		return self.__apply_bin_func( operator.sub, other )
	def __mul__(self, other):
		return self.__apply_bin_func( operator.mul, other )
	def __div__(self, other):
		return self.__apply_bin_func( operator.div, other )
	def __floordiv__(self, other):
		return self.__apply_bin_func( operator.floordiv, other )
	def __truediv__(self, other):
		return self.__apply_bin_func( operator.truediv, other )
	def __mod__(self, other):
		return self.__apply_bin_func( operator.mod, other )
	def __pow__(self, other):
		return self.__apply_bin_func( operator.pow, other )

	def __radd__(self, other):
		return self.__apply_rbin_func( operator.add, other )
	def __rsub__(self, other):
		return self.__apply_rbin_func( operator.sub, other )
	def __rmul__(self, other):
		return self.__apply_rbin_func( operator.mul, other )
	def __rdiv__(self, other):
		return self.__apply_rbin_func( operator.div, other )
	def __rfloordiv__(self, other):
		return self.__apply_rbin_func( operator.floordiv, other )
	def __rtruediv__(self, other):
		return self.__apply_rbin_func( operator.truediv, other )
	def __rmod__(self, other):
		return self.__apply_rbin_func( operator.mod, other )
	def __rpow__(self, other):
		return self.__apply_rbin_func( operator.pow, other )

	# bitwise
	def __and__(self, other):
		return self.__apply_bin_func( operator.and_, other )
	def __or__(self, other):
		return self.__apply_bin_func( operator.or_, other )
	def __xor__(self, other):
		return self.__apply_bin_func( operator.xor, other )

	def __rand__(self, other):
		return self.__apply_rbin_func( operator.and_, other )
	def __ror__(self, other):
		return self.__apply_rbin_func( operator.or_, other )
	def __rxor__(self, other):
		return self.__apply_rbin_func( operator.xor, other )
	
	def __rshift__(self, other):
		return self.__apply_bin_func( operator.rshift, other )
	def __lshift__(self, other):
		return self.__apply_bin_func( operator.lshift, other )

	# Comparison
	def __lt__(self, other):
		return self.__apply_bin_func( operator.lt, other )
	def __le__(self, other):
		return self.__apply_bin_func( operator.le, other )
	def __eq__(self, other):
		return self.__apply_bin_func( operator.eq, other )
	def __ne__(self, other):
		return self.__apply_bin_func( operator.ne, other )
	def __ge__(self, other):
		return self.__apply_bin_func( operator.ge, other )
	def __gt__(self, other):
		return self.__apply_bin_func( operator.gt, other )

	def __abs__(self):
		return self.__apply_un_func( abs )
	def __neg__(self):
		return self.__apply_un_func( operator.neg )
	

X = _X(identity, identity)

Fun While Avoiding Lambda (Python)

November 1, 2008

Readers, meet X. X is a class I wrote in Python as an alternative to using lambda. It has two main features:

  1. It acts as an identity function ( so X(3) == 3, etc. )
  2. When performing operations on it, it returns a new class that acts as a corresponding function.

Let me explain. Doing X+2 will return a new class that whenever called with an argument, will return that argument added with 2. So:

>>> map( X+2, [1, 2, 3] )
[3, 4, 5]

>>> filter( X>0, [5, -3, 2, -1, 0, 13] )
[5, 2, 13]

>>> l = ["oh", "brave", "new", "world"]
>>> sorted(l,key=X[-1])
['world', 'brave', 'oh', 'new']

These operations can be chained:

>>> map(2**(X+1), range(10))
[2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]

>>> map( "P" + X[3:]*2 + "!", ["Hello", "Suzzy"] )
['Plolo!', 'Pzyzy!']

Caveats

X has a few limitations.

  • Using X twice in the same expression probably won’t work (this can be solved)
  • Since calling X evaluates it, it can’t emulate method calls. For that you have to do use call, like: X.upper.call() (‘hello’) –> ‘HELLO’.
  • Not all operations can be “captured”. For example, the “in” operator. For that you have to use X.in_( … ), like: X.in_(range(10)) (5) –> True
  • Not all attributes will be accessible
  • More problems? Likely.

Conclusion

While not innovative nor a complete solution, I believe X can be a useful replacement for some uses of anonymous functions, providing a shorter and simpler syntax which is easier to read and understand.

It is provided here in full, in hope that it will be useful to my readers (Improvements and fixes are welcome):

class _X(object):
	def __init__(self, func):
		self.__func = func

	def __call__(self, arg):
		return self.__func(arg)

	def __getattr__(self, attr):
		return _X(lambda x: getattr(self(x), attr))
	def call(self, *args, **kwargs):
		return _X(lambda x: self(x)(*args,**kwargs))

	# Containers
	def __getitem__(self, other):
		return _X(lambda x: self(x)[other])
	def __getslice__(self, a,b=None,c=None):
		return _X(lambda x: self(x)[a:b:c])
	def in_(self, other):
		return _X(lambda x: self(x) in other)

	# Arith
	def __add__(self, other):
		return _X(lambda x: self(x) + other)
	def __sub__(self, other):
		return _X(lambda x: self(x) - other)
	def __mul__(self, other):
		return _X(lambda x: self(x) * other)
	def __div__(self, other):
		return _X(lambda x: self(x) / other)
	def __floordiv__(self, other):
		return _X(lambda x: self(x) // other)
	def __mod__(self, other):
		return _X(lambda x: self(x) % other)
	def __pow__(self, other):
		return _X(lambda x: self(x) ** other)

	def __radd__(self, other):
		return _X(lambda x: other + self(x))
	def __rsub__(self, other):
		return _X(lambda x: other - self(x))
	def __rmul__(self, other):
		return _X(lambda x: other * self(x))
	def __rdiv__(self, other):
		return _X(lambda x: other / self(x))
	def __rfloordiv__(self, other):
		return _X(lambda x: other // self(x))
	def __rmod__(self, other):
		return _X(lambda x: other % self(x))
	def __rpow__(self, other):
		return _X(lambda x: other ** self(x))

	# bitwise
	def __and__(self, other):
		return _X(lambda x: self(x) & other)
	def __or__(self, other):
		return _X(lambda x: self(x) | other)
	def __xor__(self, other):
		return _X(lambda x: self(x) ^ other)

	def __rand__(self, other):
		return _X(lambda x: other & self(x))
	def __ror__(self, other):
		return _X(lambda x: other | self(x))
	def __rxor__(self, other):
		return _X(lambda x: other ^ self(x))

	def __rshift__(self, other):
		return _X(lambda x: self(x) >> other)
	def __lshift__(self, other):
		return _X(lambda x: self(x) << other)

	# Comparison
	def __lt__(self, other):
		return _X(lambda x: self(x) < other)
	def __le__(self, other):
		return _X(lambda x: self(x) <= other)
	def __eq__(self, other):
		return _X(lambda x: self(x) == other)
	def __ne__(self, other):
		return _X(lambda x: self(x) != other)
	def __ge__(self, other):
		return _X(lambda x: self(x) >= other)
	def __gt__(self, other):
		return _X(lambda x: self(x) > other)

	def __abs__(self):
		return _X(lambda x: abs(self(x)))

X = _X(lambda x:x)

Put it in x.py and import as:
from x import X