- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
/**
* better,faster OLD SCHOOL HACKS ^^
* **/
public static function compareObject(obj1:Object, obj2:Object):Boolean {
var buffer1:ByteArray = new ByteArray();
buffer1.writeObject(obj1);
var buffer2:ByteArray = new ByteArray();
buffer2.writeObject(obj2);
// compare the lengths
var size:uint = buffer1.length;
if (buffer1.length == buffer2.length) {
buffer1.position = 0;
buffer2.position = 0;
// then the bits
while (buffer1.position < size) {
var v1:int = buffer1.readByte();
if (v1 != buffer2.readByte()) {
return false;
}
}
return true;
}
return false;
}
Сравнение объектов сериализацией, по моему такого тут еще не было...
1. Циклические графы свойств делают обход и сравнение нетривиальной задачей.
2. Сравнивать не public свойства - как правило мало толку.
3. Такой метод почти наверняка используется в контексте, где задействована сериализация, и объекты произвольных типов нужно сравнивать по значению.
4. Это дает возможность при удачной реализации IExternalizable сделать эту проверку гораздо более быстрой, чем цикл с обходом всех свойств.
5. [Transient] опять же позволяет исключить какие-то свойства из такого сравнения.
6. Опять же, способ сравнить всяких наследников Proxy в которых перебор свойств может вообще быть бессмысленной задачей.
7. Можно сравнить объекты разных типов (если, например, сериализация настроена так, что на выходе получаем XML), то таким образом можно сравнить с XML.
Эта тема давно и неоднократно поднималась на флешере... Вобщем, не говнокод.
>faster
> OLD SCHOOL HACKS ^^
>var v1:int = buffer1.readByte();
1.Что это за хуйня? Человек претедует на почётное звание байтоёба. А читает в инт и сравнивает байтами. Ёбанный стыд.
var v1:int = buffer1.readInt(); if (v1 != buffer2.readInt()) {
И теоретически наш код ускоряется в 4 раза.
2.Для начала, ради приличия делают элементарные, детские проверки - на null, на идентичность типов, итд.
В общем, говнокод.
PS. Против самого способа сравнения ничего не имею против.
Нет, лёгкая небрежность, не криминал.
По реалиям флеша самый быстрый вариант будет bufferA[i] === bufferB[i], т.как вызов функции получается сильно накладным (или можно использовать какой-нибудь пост-процессор, который этот массив представит как DomainMemory, и тогда можно будет использовать инструкции быстрого доступа и читать по 4 байта за раз. Но скорее всего байтов там совсем не много получается. Двузначное число и очень редко трехзначное. Так что не стоит.
Вам виднее.
>Реализация херовая, но задумка годная
Не спорю.
>Лёгкая небрежность, не криминал.
Да если б не коммент faster OLD SCHOOL HACKS не плюсанул бы.
чисто так - private/protected поля тоже сериализуются
> 4. Это дает возможность при удачной реализации IExternalizable сделать эту проверку гораздо более быстрой, чем цикл с обходом всех свойств.
а выделение памяти под буфера нынче бесплатное?
> 5. [Transient] опять же позволяет исключить какие-то свойства из такого сравнения.
а еще можно написать нечто компараторо-подобное, и так же исключить
> 7. Можно сравнить объекты разных типов (если, например, сериализация настроена так, что на выходе получаем XML), то таким образом можно сравнить с XML.
А во что сериализуется XML, полученный на входе?
Про XML вы не поняли: у вас есть XML полученный откуда-то и ваш объект, и вам нужно сравнить XML с этим объектом. Задача возникает очень часто, если нужно показать какие-нибудь данные, которые часто обновляются, и получаются из внешнего источника.
Реализовать Comparator - ага, успехов вам в этом нелегком. Только сначала потрудитесь выяснить сколько головной боли это стоило, например, в той же Яве, и как долго (да, вобщем-то и до сих пор) это было причиной разного рода непредвиденных ошибок. Вы тут одной реализацией не отделаетесь, т.как нужно будет очень много чего предусмотреть.
Как пример: сравниваем два таких объекта:
Ну и это не отменяет проблем с Proxy и наследниками, да и вообще со всякими объектами, к которым уже доступа нет их поменять.
> Ох боже... памяти на этот буффер выделится аж просто немеряно.
А это уже зависит от глубины вложенности полей. Сериализация одного объекта может утянуть за собой граф из 1000 привязанных.
> Реализовать Comparator - ага, успехов вам в этом нелегком. Только сначала потрудитесь выяснить сколько головной боли это стоило, например, в той же Яве, и как долго (да, вобщем-то и до сих пор) это было причиной разного рода непредвиденных ошибок. Вы тут одной реализацией не отделаетесь, т.как нужно будет очень много чего предусмотреть.
Intellij IDEA -> Alt-Insert -> hashCode() and equals() помогает в 99% случаев.
В вашем же примере вы сравниваете ССЫЛКИ. Они как ни странно - разные. В Java есть Arrays.equals() для этого случая.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/ByteArray.html#toJSON() - кстати, тоже можно заюзать наверное.
AS программисты жалуются на то, что аллокатор медленно работает? А Явисты не? Да даже те, кто пишут на Си - тоже жалуются. Жаловаться - это профессиональная привычка программистов, от языка практически не зависит.
Полагаю если адобе не мудаки, то должны были сделать его ленивым, как потоки.
Если же вывод в примере не идет в потокообразный объект - тогда говно, да.
И только потом только сравнить их?
Безо всякой асинхронности?
Вы собираетесь создавать equals / getHashCode - для всех встроенных объектов? Как, если не секрет? А их есть несколько сотен разновидностей. А к ним в придачу библиотечные классы, которых может быть тысячи. Откуда у вас возьмется столько рвения и терпения их всех написать?
А написать equals, например, для циклических связных списков?
Или для объектов, которые уже реализовали equals, но не так, как вам нужно.
А как вы будете сравнивать представителей класса с представителями его подклассов, и наоборот?
Более того, такая функция скорее всего могла понадобиться для работы с объектами, которые попадают уже в сериализованом виде, и их нужно сравнить с уже имеющимися, чтобы понять нужно ли делать замену, или нет. Такая ситуация часто возникает при работе с флексовыми сервисами типа Блейза, где почти все объекты которыe передаются с сообщениями наследники / экземпляры ObjectProxy - для которого, уж поверьте, очень нетривиально написать equals который бы хоть что-то вменяемое делал.
Я могу просто сравнить свойства.
> Вы собираетесь создавать equals / getHashCode - для всех встроенных объектов? Как, если не секрет? А их есть несколько сотен разновидностей. А к ним в придачу библиотечные классы, которых может быть тысячи. Откуда у вас возьмется столько рвения и терпения их всех написать?
Я думаю, встроенные классы не тупые, и умеют сравниваться. Ну это было бы логично.
> А написать equals, например, для циклических связных списков?
for each? не, не слышал...
> А как вы будете сравнивать представителей класса с представителями его подклассов, и наоборот?
а как тут сериализация поможет? В сериализованном виде дескриптор БУДЕТ отличаться для родителя и потомка - фейл.
> Такая ситуация часто возникает при работе с флексовыми сервисами типа Блейза, где почти все объекты который передаются с сообщениями наследники / экземпляры
И?
Являются ли массивы [1, 2] и [1, 2] одинаковыми? А если x = [1, 2] x[x] = x и y = [1, 2], одинаковы ли x и y? А если это словарь, имеет ли значение тот факт, что ключ в нем равен 1 или "1"? А как вы об этом узнаете?
Вы "думаете" что встроенные классы умеют сравниваться, а в справку не заглянули, но тем не менее спорите?
Сериализация для классов, которые не декларировали registerClassAlias будет делаться так, как будто сериализуется обычный объект, поэтому, если значения полей совпадут, то и будут равны, не важно в какой степени родства находятся.
Сорри, вы либо совсем новичек в этом языке, либо его вообще не знаете. Лучше начните со справки, а потом приступайте к обвинениям.
Зачем нужны такие классы? Это отказ от ООП какой-то, точнее переход на HashMap-oriented OOP.
> Являются ли массивы [1, 2] и [1, 2] одинаковыми?
Да, есть такой цикл - for each называется.
> А если это словарь, имеет ли значение тот факт, что ключ в нем равен 1 или "1"? А как вы об этом узнаете?
Имеет. В 1 случае ключом является число, в другом строка. Почитайте про типизацию, это интересная тема. Хотя судя по комментам, передо мной выходец из PHP и поклонник HashMap-oriented OOP
> Вот жеж... нет, вы не можете просто сравнить свойства. См. пример выше. Свойства могут иметь значения (и очень часто таки имеют такие значения), которые вы "просто" сравнить не можете.
Добавил в цитатник
А по поводу словаря - ну, хорошо, это вы сейчас так решили. А что будет завтра, когда вы решите по-другому? А что, если за вас уже кто-то решил, по-другому? Предположим, узнать есть ли в словаре два разных ключа "1" и 1 не сериализируя его вы вообще совсем никак не сможете. Это скорее недостаток в реализации словаря как такового, но тем не менее, так оно работает и с этим жить.
О, я знаменит, меня теперь начинающие цитируют!
Чего? Я про инкапсуляцию слышал.
> сериализация
В мое время там была абстракция.... Хотя наверное
"чет я совсем отстал от новых веяний в ООП."
По поводу классов и подклассов - всем будет жить гораздо проще, если base.equals(derived) и derived.equals(base) всегда будут возвращать false. Это правильно в 99.999% случаев, т.е. когда при наследовании не добавляются новые поля. Иначе сложно обеспечить симметрию и транзитивность equals.
А так:
Ситуация, как правило, следующая: показываем очень быстро обновляющуюся таблицу, например биржевые сводки курсов валют, или что-то в этом духе. Данные в таблице обновляются не все одновременно, а что пришло - то и обновили. Чтобы выяснить, нужно ли обновлять строчку / столбец нужно выяснить имеет ли это практический смысл (т.е. изменится ли что либо с точки зрения пользователя), иначе изза тяжеловесного интерфейса будут тормоза. И в этом случае настоящие - а не выдуманные типа тех, которые могут быть вызваны паузами мусорщика.
Что до сравнений - в контексте этой задачи, как правило не нужно принимать во внимание родство между классами, т.как это чаще всего техническая деталь, которая не имеет отношения к задаче - не факт, что все объекты с одним и тем же значением были получены одинаковым способом. Иногда это не возможно по сугубо техническим причинам, например - закрыто наследование от какого-то встроенного класса.
Не смотря на то, что в книжках по Яве этому уделяется глава - этот аспект, как правило создает много головной боли, и тем больше, чем менее тривиальный объект. Что касается разницы с АС, то особенным моментом являются прокси объекты, которые могут управлять перечислением своих свойств (могут их даже создавать и удалять на ходу), могут неадкватно (с точки зрения сравнения) реагировать на вопрос "а есть ли свойство", "а есть ли еще свойства" и "а равно ли свойство чему-то". Ну и кроме того, свойства в АС - могут быть сложными функциями, а ключи могут быть и не строками вовсе, и в таком случае получение списка свойств - это очень заморочливая процедура.
С чего это вдруг? Если бы наследники должны были возвращать одинаковые с базой выходы для одинаковых входах, смысла в наследовании было бы мало.
Лисков требует отсутствие нарушения семантики и контрактов при наследовании, и с equals тут всё совершенно прекрасно, семантика чётко соблюдена.
Ну кто-то недавно с пеной у рта рассказывал про "неправильное ООП в js", и что там "нет контроля за типизацией" а теперь же наоборот отстаивает нетипизированное, динамическое сравнение.
> переход на HashMap-oriented OOP
Вот-вот. Это ж суть js.
А в лиспе, похоже, Tuple oriented OOP
Это, кстати может оказаться интересной темов в, например, vObj исчислении. Вполне потянет на статью, если даже не тему для исследовательской работы.
Флешепроблемы. Или же вы просто не умеете их сравнивать.
В общем не буду читать эти простыни, а отплюсую @костоправа.
- вы не пишете на АС, поэтому вам все равно как оно будет, или не будет работать. Ну и ваше мнение не то чтобы совсем высосано из пальца, но опирается на реалии совсем другого языка, которых просто нет в этом контексте.
- костоправ - очень самонадеяный Ява-писатель, который по неопытности набрел на какой-то код, который не понял, но решил, что это плохо, потому что в Яве это можно сделать по-другому.
Что получится врезультате: скорее всего костоправ запилит копию явовских equals, потом будет очень долго воевать с существующей системой, которая в его мирок никак не будет укладываться. А потом, скорее всего бросит это дело / локально пофиксит несколько явных проблем. Потом перейдет в другой отдел и будет с ужасом вспоминать о проделаной работе.
Хуже всех будет тем, кому достанется в поддержку задел оставленный костоправом, на поддержку / переделку.
Случалось много раз.
Будет больше похоже на правду.
Если эту функцию использовали там, где можно было сравнить ссылки - тогда бы ее удаление / замена была бы оптимизацией, а если нет - вероятность того, что вы что-то существенно улучшили бы заменив ее equals стремится к нулю.
Но вот ваши выводы про типизацию: у Явистов как бы и альтернативы никакой нет... любят не любят - в Яве никакой динамической типизации не будет в обозримом будущем. В АС есть разные подходы, и, хоть я и не сторонник, но иногда потеря типизации оправдана. Как аргумент в защиту: это сокращает код. Делает его более понятным убирая технические детали. Позволяет делать код более модульным, совместимым с будущими добавками и изменениями.
Флексовый фреймворк, с другой стороны, написан явистами, которые плохо знали АС, и поэтому он такой какой он есть... с массой неидеоматического кода, заимствоваными бесполезными идеями и условностями.
> Как аргумент в защиту: это сокращает код. Делает его более понятным убирая технические детали. Позволяет делать код более модульным, совместимым с будущими добавками и изменениями.
Особенно потом легко разбираться, что в какой переменной лежит - массив, объект, а может быть вообще число. Бесспорно, легко добавлять новый функционал.
Скала (так же известная как JML),
Питон,
Эрланг,
Камл,
В Лиспе аннотации типов опциональные и их используют только в случае необходимости оптимизации,
Руби,
Смолток (Стронгток - опциональный довесок),
ПХП,
ж. скрипт,
Хекс (опциональное, как в Скале, Камле или Лиспе) - но об этом вы наверное не слышали.
Я так подозреваю, что Перл и Луа - так же устроены, но не пользовался ими никогда.
Этим исчерпываются мои познания, но языков таких много и на них написаны иногда очень большие приложения в сотни тысяч строк.
Ключ к разгадке: просто выводим типы, пишем их рядом со словами - и все становится на свои места.
Lua подобно AS поддерживает разные парадигмы типизации.
http://govnokod.ru/12741#comment172084
Насколько интуитивен код ?
А, так там вообще compareObjects