среда, 16 мая 2007 г.

Кроссбраузерность

Такой код


<textarea id="t">
123
123
123
123
</textarea>
<script>
var t = document.getElementById('t');
alert(t.value.length+", "+
t.value.charCodeAt(3)+", "+t.value.charCodeAt(4));
</script>

под Firefox'ом (1.5.0.11) выдает
16, 10, 49

а под IE 7.0
20, 13, 10

Напомню, что ASCII-код '\r' равен 13, а '\n' равен 10.
Таким образом файрфокс переносы строк обрабатывает как '\n' а IE как '\r\n' в текстовых полях. Но что характерно, оба браузера при сабмите шлют на сервер '\r\n', такая вот небольшая несуразность с файрфоксом. Проблема с этим у меня возникла при клиентской валидации длины вводимого текста. При этом на файрфоксе в некоторых случаях клинентская валидация проходила успешно, а серверная нет.


пятница, 11 мая 2007 г.

ООП, замыкания, или изобретая велосипеды...

Тут одна занятная штука нарисовалась. Вот возьмем объект (экземпляр класса) из ООП. Упрощенно, его методы можно считать обычными функциями, в контекст которых захвачена переменная this (или self, кому что нравится). Поясню на примере языка Python, что такое замыкание.


def makeAdder(num):
def adder(num1):
return num + num1
return adder

sevenAdder = makeAdder(7)
print sevenAdder(2) # => 9

В данном случае вложенная функция adder при своем создании захватывает окружающий ее контекст. В частности, в этом контексте оказывается переданная в функцию makeAdder переменная num.
И вот пришла идея создать на такой основе что-то вроде ООП. Вот что в результате получилось:
from bicycleoop import *

@klass()
def Superclass(this, kls):
kls.AAA = 'Superclass_AAA'

@method
def say1():
print 'from super.say1: [arg1 = %s];' % this.arg1

@method
def say3():
print 'from say3;'

@method
def say5():
print 'from say5:',
this.say2()

@method
def say6():
print 'from super say6;'

@method
def say7():
print 'from say7: this.AAA='+this.klass.AAA, 'super.AAA='+this.super.klass.AAA

@klass(Superclass)
def Klass1(this, kls):
kls.AAA = 'Klass1_AAA'

@klassmethod
def klm1():
print 'KlassMethod1: Klass1.AAA='+kls.AAA, 'Superclass.AAA='+kls.superClass.AAA

@method
def __init__(arg1, arg2):
print 'creating instance of %s with arg1=%s, arg2=%s' % (this.klass.name, arg1, arg2)
this.arg1 = arg1
this.arg2 = arg2

@method
def say1():
print "from say1: [arg1 = %s]" % this.arg1

@method
def say2():
print "from say2: [arg2 = %s]" % this.arg2,
this.say1()

@method
def say4():
print 'from say4:',
this.say3()

@method
def say6():
print 'from say6:',
this.super.say6()

print Superclass.AAA # => Superclass_AAA
print Klass1.AAA # => Klass1_AAA

k = Klass1.new(17, "Hello") # => creating instance of Klass1 with arg1=17, arg2=Hello
k.say1 # => from say1: [arg1 = 17]
k.super.say1() # => from super.say1: [arg1 = 17];
k.say2() # => from say2: [arg2 = Hello] from say1: [arg1 = 17]
k.say3() # => from say3;
k.say4() # => from say4: from say3;
k.say5() # => from say5: from say2: [arg2 = Hello] from say1: [arg1 = 17]
k.say6() # => from say6: from super say6;
k.say7() # => from say7: this.AAA=Klass1_AAA super.AAA=Superclass_AAA

k1 = Klass1.new(20, "sdfs") # => creating instance of Klass1 with arg1=20, arg2=sdfs
k.say2() # => from say2: [arg2 = Hello] from say1: [arg1 = 17]
k1.say2() # => from say2: [arg2 = sdfs] from say1: [arg1 = 20]

print Superclass.AAA # => Superclass_AAA
print Klass1.AAA # => Klass1_AAA

Klass1.klm1() # => KlassMethod1: Klass1.AAA=Klass1_AAA Superclass.AAA=Superclass_AAA

sup = Superclass.new()

print k.methods.keys() # => ['say7', 'say6', 'say5', 'say4', 'say3', 'say2', 'say1', '__init__']
print sup.methods.keys() # => ['say7', 'say6', 'say5', 'say3', 'say1']

print k.klass == Klass1 # => True
print k.super.klass == Klass1.superClass == Superclass # => True

o1 = obj()

Klass1(o1, Klass1)
o1.arg1 = 15
o1.say1() # => from say1: [arg1 = 15]

Как видим, реализовано наследование (одиночное, правда), обычные и статические методы (методы класса), и статические поля тоже. Создание объектов реализовано в стиле Смоллтолк и Руби (через Klass.new). В объявлении класса передаются 2 переменные (this и kls), что кажется немного странным. Но это, во-первых, более pythonic (Explicit is better than implicit) а, во-вторых, это как раз те переменные, которые будут "замкнуты" в замыкания из функций-методов. Замечу, что они инициализируются лишь в момент создания объекта.
Для выразительности объявление классов и методов выполненно в виде декораторов. Декоратор (для тех, кто не в курсе) это функциональность, работающаю следующим образом: код

@decor
def f(arg):
# do smth
pass
эквивалентен коду:

def f(arg):
# do smth
pass

f = decor(f)

То есть декоратор - это обычная функия, которой мы "декорируем" некоторую другую функцию. Я полагаю это имеет отношение к AOP и вероятно, этот механизм призван внести большую выразительность и декларативность в код. Подробнее про декораторы читать тут.
А вот описание модуля с декораторами:
# this is file bicycleoop.py
import sys

def obj():
def _obj():pass
return _obj

def klass(*args):
# args - superclasses, now only 1 allowed
def classDecorator(classFunc):
if len(args) == 1:
_superClass = args[0]
else:
_superClass = None

def copyMethodsTo(this):
this.klass = classFunc

if _superClass:
this.klass.superClass = _superClass
this.klass.superClass.copyMethodsTo(this)# now into this exist all functions with captured 'this'
this.klass = classFunc # return back after ^^^ changes it
this.super = obj()
this.super.klass = _superClass
for meth in this.methods.keys():
setattr(this.super, meth, this.methods[meth])
else:
classFunc.superClass = None

this.klass(this, obj()) # initing methods
return this

def new(*a, **k):
this = obj()
copyMethodsTo(this)
this.__init__(*a, **k)
return this

classFunc.copyMethodsTo = copyMethodsTo
classFunc.new = new
classFunc.name = classFunc.func_name

classFunc(obj(), classFunc) # for class vars and class methods

return classFunc

return classDecorator

def method(methodFunc):
this = sys._getframe().f_back.f_locals['this']
setattr(this, methodFunc.func_name, methodFunc)
if not hasattr(this, 'methods'):
this.methods = {}
this.methods[methodFunc.func_name] = methodFunc
return methodFunc

def klassmethod(methodFunc):
kls = sys._getframe().f_back.f_locals['kls']
setattr(kls, methodFunc.func_name, methodFunc)
if not hasattr(kls, 'klassmethods'):
kls.klassmethods = {}
kls.klassmethods[methodFunc.func_name] = methodFunc
return methodFunc

Тут есть пару моментов. Такой вот замысловатый код:

sys._getframe().f_back.f_locals['this']

используется, чтоб подняться вверх по стеку вызовов функций и получить из локального контекста внешней функции необходимые переменные. А второй довольно смешной хак тут - использование все тех же функций в качестве объектов (функция obj на самом деле возвращает новую пустую функцию, которую мы используем совсем не по назначению))), которым можно присваивать любые поля, ввиду того, что такой код, как видим, не хочет работать:

>>> o = object()
>>> o.a = 123

Traceback (most recent call last):
File "", line 1, in
o.a = 123
AttributeError: 'object' object has no attribute 'a'
>>>

Заключение:

Полезность (практическая) этого дела нулевая, но позволяет хорошенько размять мозг. И, кроме того, получилось довольно концептуально: ключевое слово языка class использовано не было. Правда опять же, ООП-природа языка была использована, по этому все довольно не честно, но мы никому ничего и не были обязаны =)

PS. Извините за длинный пост. Кто-нибудь может подсказать как показывать только часть поста со ссылкой "читать далее" на лицевой странице?


вторник, 8 мая 2007 г.

Smalltalk, въезд

Ну что. Расскажу я вам немного про Смоллтолк. Наверное, все (нормальные) программисты слышали такое слово как Смоллтолк, и что это есть дедушка всех ООП языков. Все это так, но мало кто знает, что это действительно очень концептуальный и интересный язык.
Что же в нем такого интересного? В общем то основные фичи языка можно прочитать тут и тут. В двух словах: все - суть объекты, которые общаются посредством сообщений (эквивалент сообщения - вызов метода).
Интересное начинается дальше. В смоллтолке все программы как бы неразрывны, более того, в смоллтолке все есть одна большая неразрывная программа. Другими словами, эта большая программа - смоллтолк-система, которая вертится на виртуальной машине. Виртуальная машина, как вы могли догадаться, написана на смоллтолке :-). При этом С-рантайм, на котором собственно вертится эта виртуальная машина очень маленький, например у Squeak исполняемый файл весит всего 1 Мб, что даже меньше чем размер текущей версии флэш-плеера!!! Основная же функциональность вынесена в виртуальную машину, которая в Squeak на данный момент весит ~17 Мб. За счет такого положения дел Squeak чрезвычайно хорошо портируем ). Похожим может похвастать Java. В ней тоже основные библиотеки (коллекции, IO, регекспы, дата-время, графич. библиотека) написаны на ней самой, благо скорость работы Java'ы это позволяет. Преимущества такого подхода очевидны. На текущий момент ни питон ни руби не могут похвастать подобным (. Подробнее об архитектуре можно прочитать тут и тут.
Однако, отвлеклись )). Архитектура смоллтолка в реализации Squeak выглядит так: на маленьком си-рантайменном ядре вертится виртуальная машина, на виртуальной машине вертится смоллтолк-система.
Сама смоллтолк-система тоже очень интересная сущность. Это исключительно динамичная (абсолютно все параметры системы можно менять на лету) система. Сказать кратко - это мини-ось, а что, в качестве шелла Workspace+Transcript, в качестве скриптового языка - его величество, Смоллтолк, рабочий стол, Morphic'овские окошки, графика (1, 2, 3))) Только не смейтесь, реализация в виде ОС тоже есть).
В смоллтолке реализована так называемая инкрементальная компиляция. Т.е. создавать классы и методы, а так-же менять методы вы можете на лету. При этом каждый раз, когда Вы говорите системе Accept некоторый код, этот код компилируется. Это возможно, потому что в Смоллтолк-системе существует порожденный экземпляр компилятора, который и выполняет данную работу)) Продолжая параллели с Java'ой - в джаве тоже замечательно, что компилируя проект, вы компилируете только еще не скомпилированные классы, при этом вам совершенно не нужно иметь исходники используемых библиотек.
Кроме того Смоллтолк предоставляет поистине невообразимые, чудовищные, колоссальные, уникальные, невероятные (эко меня торкнуло) средства для интроспекции уже работающей программы (кода). Тем более невероятно, вы можете воздействовать на работающую программу (изменять ее параметры) прямо на лету, и вам для этого не нужно ставить брекпойнты, проходить в пошаговом режиме (как в Java), вы как бы можете вклиниваться в работающую программу и подхачивать ее, не останавливая. Небольшой наглядный пример. Перед вами окошко, в котором летают шарики, отбаваясь от стенок (типа, модель газа). Вы в состоянии затормозить часть шариков, удалить, перекрасить, наблюдать за изменением их скоростей, все это на лету (Используя Inspect It, Explore It).
И вот таким динамизмом эта среда пронизана польностью ).
Что еще интересного. Исключения. В смоллтолке они особенные. Взять Java'у. В ней, если произошло исключение, стек вызовов методов как бы "раскручивается", и мы попадаем в некоторый catch блок. В смоллтолке все хитрее!! Там стек не раскручивается. И после произошедшего исключения вы можете продолжить выполнение программы. Пример. Вы написали код, запускаете - упс, исключение - перед вами возникает окошко с названием исключения, стеком вызовов, и тремя кнопками (Proceed, Abandon, Debug). Вы по стеку вызовов перемещаетесь в точку возникновения исключения, исправляете, делаете Accept, и жмете Proceed, программа побежала дальше. Красота )) В какой Java'е, Python'е, Ruby это возможно?
Ну и последнее. Когда вы выходите из системы она (система) сохраняется на диск в виде образа. Образ - это есть дамп запущенной (работающей) системы! Там хранится весь введенный вами код, все запущенные программы, все установленные пакеты, и т.д. По сути вся система (та самая большая живая неразрывная программа) сериализуется на диск. А при следующем запуске загружается! Это очень удобно, хоть и довольно непривычно. (Предствьте, у вас запущен сервер. Вы выключаете систему, затем через время включаете, и севрер вновь запущен как ни в чем не бывало). Можно иметь несколько образов с разным набором установленного ПО, или с разной конфигурацией, кроме того разные довольно большие проекты (Seaside, Croquet) имеют обыкновение распространяться в виде отдельных образов, хотя обычно их можно установить и как пакеты.
Ладно, пока достаточно ). Тут еще не затронуты вопросы о континуациях (продолжениях), блоках кода (замыканиях) и других интересных вещах. Но хорошего по немножку. До связи!
UPD. Сдается мне в архитектуру вкралась досадная неточность, на самом деле, виртуальная машина написанная на смоллтолке автоматически конвертируется в исходники си, которые затем компилируются в исполняемый код. Это удобно, т.к. можно отлаживать виртуальную машину в смоллтолк-среде, а потом когда все работает как надо автоматически получить корректные ее си-исходники. Вот так то)


пятница, 4 мая 2007 г.

Пожалуй, начнем...))

Надо что-то написать в первом посте... Блин, это мой первый блог, не знаю с чего начать))
Ну в общем так.. Я завел блог, во-первых, потому, что это нынче модно, ну а во-вторых, потому что хочу поделиться с вами (моими будущими читателями) тем что мне интересно, и, возможно, заинтересовать Вас в этом.
Немного о себе: 21 год, студент МФТИ, 5 курс, работаю программистом-аналитиком в некой оффшорной компании, занимаюсь J2EE-технологиями.
Что же все таки мне интересно: разумеется Java, хотя, впрочем как и все остальное: различные интересные концептуальные языки программирования (Python, Ruby, Smalltalk), вообще философия программирования, веб-технологии, agile development, как впрочем и RIA (в прошлом работал Flash-погромистомпрограммистом), да и сейчас приходится иногда садиться за Flex, хотя в некоторых кругах его вполне обоснованно принято ругать, Flash, AJAX, ... Так, что-то точно упустил, ну ладно, потом наверстаем))
Добавлю вот еще что, моя позиция такова - нужно использовать тот инструмент, который вам нравится использовать и с которым вы продуктивны, однако здравого рационализма и постоянного самосовершенствования и поисков (нового|лучшего) никто не отменял.
До связи!