Как не забыть порядок параметров

Обсуждаются как существующие проекты (перевод документации, информационная система и т.п.), так и создание новых.

Модератор: Модераторы

Re: Как не забыть порядок параметров

Сообщение Mirage » 09.04.2014 19:39:21

скалогрыз писал(а):....ээээ, никогда бы не подумал, что "выучивание" это путь к ошибкам. Скорее наоборот :) Невыучивание чего угодно, ведёт к непредасказуемым результатам.


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

скалогрыз писал(а):Не зря. Я уже привёл технические проблемы.
...
1. инфраструктура удваивается (кроме самого класса - нужно написать ещё один класс - конструктор)
2. нет чёткого описания какие методы критичны при строительстве (ведь можно и забыть!). например:
3. создание класса очень дорогая операция получается! (на каждый параметр 1 вызов метода!!) - это дорого и жирно.
4. такая "фабрика" есть замаскированные глобальные переменные. Hinst - лично для тебя - подумай, сможешь ли ты использовать 1 фабрику, из двух

эти?
1 - да, билдер дублирует все поля, но не логику.
2 - говорилось уже, все критичные в конструкторе билдера. Остальные опциональные.
3 - вызов метода это не дорого совершенно. Такие методы вообще должны инлайниться.
4 - ничего глобального там и близко нет. Очевидно, что билдер должен использоваться только при конструировании.

скалогрыз писал(а):Особенно для паскаля, где вместо билдера можно описать функцию, которая сделает необходимые инциализации (и при этом останется потоко безопасной). Более того, если функция описана в самом модуле описания класса, то функция может произвести инициализации ещё эффективнее, т.к. будет доступ к private полям.


Где гарантия, что когда функция вернет ссылку на сконструированный класс, все поля будут проинициализированы?

скалогрыз писал(а):А если обязательных ни два и не три параметра? А если опять человек не помнить какие-там параметры и в какой последовательности передовать?


Еще раз: билдер нужен для решения проблемы конструирования immutable классов с необязательными полями.

скалогрыз писал(а):Будет ли уместным спросить - зачем immutable объекты? Самое критичное место (строки) в паскале разрулено, использованием счётчиков.


Очень правильный вопрос.
Immutable объекты очень удобны, именно своей неизменностью. Вот это, похоже, из функционального программирования пришло.
В многопоточном программировании они особенно полезны, т.к. не требуют синхронизации. Можно создавать в одном потоке, использовать в других, не грея голову. Можно даже изменять, но при этом создается новый экземпляр.
В книге, переводом части которой является вышеупомянутая статья на Хабре, довольно много внимания уделено иммутабельным объектам. И не зря.

stanilar писал(а):Касательно сути исходного вопроса - ну не умеет IDE читать мысли, не научили еще. Пока еще нужно самому напрягаться.


Есть такие IDE, что иногда закрадывается подозрение, будто мысли они таки читают.

hinst писал(а):Между прочим есть такой прикол, что в FPC такая похожая фигня, ну почти такая же, есть уже:


Я даже больше скажу:
В FPC есть механизмы, позволяющие вызывать метод так:
method(param1 = 1, param2 = 'строка');
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Как не забыть порядок параметров

Сообщение hinst » 09.04.2014 20:36:57

ну и где эти механизмы??? как их задействовать?
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Как не забыть порядок параметров

Сообщение скалогрыз » 09.04.2014 21:55:54

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

не надо выучивать всё. Нужно выучить наиболее часто используемые... тот же Pos. Да и человеческое мышление заставляет такие вещи "кешировать", так что выучивание происходит бессознательно. (и sign тому пример!)

Mirage писал(а):
скалогрыз писал(а):Не зря. Я уже привёл технические проблемы.
...
1. инфраструктура удваивается (кроме самого класса - нужно написать ещё один класс - конструктор)
2. нет чёткого описания какие методы критичны при строительстве (ведь можно и забыть!). например:
3. создание класса очень дорогая операция получается! (на каждый параметр 1 вызов метода!!) - это дорого и жирно.
4. такая "фабрика" есть замаскированные глобальные переменные. Hinst - лично для тебя - подумай, сможешь ли ты использовать 1 фабрику, из двух

эти?
1 - да, билдер дублирует все поля, но не логику.
2 - говорилось уже, все критичные в конструкторе билдера. Остальные опциональные.
3 - вызов метода это не дорого совершенно. Такие методы вообще должны инлайниться.
4 - ничего глобального там и близко нет. Очевидно, что билдер должен использоваться только при конструировании.

да, они самые.
1. Ну и зачем программисту заниматься написанием дублежа? к тому же дублежа данных.
Ведь задача программиста писать алгоритмы - логику! Лучше больше времени на алгоритм потратить, чем выстраивать (и поддерживать) инфраструктуру.

2.
Mirage писал(а):говорилось уже, все критичные в конструкторе билдера. Остальные опциональные.
Еще раз: билдер нужен для решения проблемы конструирования immutable классов с необязательными полями.

Так в этом и вопрос: что если обязательных полей много (понятие "много" - субъективное понятие, для кого-то 5 полей в конструкторе - много, для кого-то 100 много)
Означает ли это две вещи:
* нельзя использовать builder в данном случае ? (т.е. всё-равно все параметры пойдут в конструтор)
* нужно создавать дополнительные builder-ы для builder-ов?

Mirage писал(а):3 - вызов метода это не дорого совершенно. Такие методы вообще должны инлайниться.

Дорого! Особенно если вызвов метода занимает больше времени от процессора чем тело самой функции.
А для билдера это очень свойственно, потому что кроме сохранения данных, ему ещё нужно вернуть ссылку на себя. Т.е. это как минимум две операции, вместо одной, + расход на вызвов самого метода - заполнение регистров и стэка.

Инлайнить всё подряд просто нехорошо и пагубно сказывается на размерах кода.

Mirage писал(а):4 - ничего глобального там и близко нет. Очевидно, что билдер должен использоваться только при конструировании.

Вообще-то очень даже глобальны. Почему.
1) это объект, и создание объекта это операции с динамической паматью и для экономии времени, обычно принято объекты переиспользовать. Т.е. логично создать 1 билдер, а потом его использовать чтобы пораждать много реализаций.
А иначе получается двойной расход на создание объекта: * сначала создай билдер * потом создай объект * потом билдер освободи.???
2) раз объект создан один раз, то руки чешутся не создавать билдеры для каждого потока, а надо. (К тому же, если билдеры нужны для создания immutable объектов, которые как-раз хороши для много поточности?!)

скалогрыз писал(а):Где гарантия, что когда функция вернет ссылку на сконструированный класс, все поля будут проинициализированы?

Реализацией самой функции.
Т.е. на тех же самых гарантиях, что и вызов "build()" в builder-е гарантирует инициализацию всех полей.
Если функция решит, что переданные данные неправильные, или недостаточны, то она может либо вернуть nil, либо кинуть exception (по-вкусу).

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

Mirage писал(а):В многопоточном программировании они особенно полезны, т.к. не требуют синхронизации. Можно создавать в одном потоке, использовать в других, не грея голову. Можно даже изменять, но при этом создается новый экземпляр.

Очень бюось, что такие проблемы исключительно языковые.
Проблема синхронизации, решается алгоритмически - программист знает как будет использоваться тот или иной объект.

А вообще, глядя на примеры использования, у меня складывается впечатление, что это не какой-то вид объектов, а некий приём или подход в программировании. Почему, потому что ни один язык не предоставляет возможности описания immutable объектов. Вместо этого программист обязан, написать необходимые защитные методы.... ну да, и как итог написать билдеры :)

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

Mirage писал(а):В многопоточном программировании они особенно полезны, т.к. не требуют синхронизации.

Нужно заметить, что они не требуют синхронизации, потому что являются read-only.
Если два потока могут зависят от изменённых данных, immutable объекты внезапно приводят к ошибкам.
Т.к. либо не видят изменённых данных, либо каждый работает со своей копией данных.
Нужно заметить, что read-only подход можно использовать не вводя такого понятия как "immutable object" дабы себе мозг не загромождать :)

Mirage писал(а):Есть такие IDE, что иногда закрадывается подозрение, будто мысли они таки читают.

Код нужно писать так, чтобы его можно было понимать и изменять не имея под рукой удобной IDE.

P.S: Интересный список!.Билдеры попадают под понятие "Полтергейст" :mrgreen:

Добавлено спустя 14 минут 53 секунды:
А в паскале невозможно сделать immutable объект в принципе - с точки зрения потоковой безопасности!
Очень просто, как минимум один момент всегда нужно будет синхронизировать - это момент уничтожения объекта.
В Java с этим проблем нет, ибо сборка мусора, а в паскале нужно следить, что потоки закончили своё чтение объекта, до того как от этого объекта избавится.

И объект тут не обязательно должеть class или object, это может быть и переменная в стеке. (уж с чем потоку нужно работать).
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Как не забыть порядок параметров

Сообщение hinst » 09.04.2014 22:12:46

давайте решать проблемы, а не создавать.
@Mirage
Скажи плз, что за фича в FPC с вызовом методов с именованными параметрами, про которую ты пишешь

Добавлено спустя 4 минуты 12 секунд:
COM интерфейсы что ли? госпаде...... :roll: :roll: :roll: :shock: :shock: :shock: :shock:
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Как не забыть порядок параметров

Сообщение sign » 10.04.2014 06:59:06

В частности, я вот так делаю и не парюсь по поводу порядков параметров:
Код: Выделить всё
procedure InitqTbl(Q: TSQLQuery);
procedure InitqTbl(Q: TSQLQuery; const aSQL: String);
procedure InitqTbl(Q: TSQLQuery; const Arr: Variant; const aSQL: String = '');
...
   
   // Прочитать список лиц, которые купили данный продукт в данном месяце
    InitqTbl(DM.qGetBuyCons, VarArrayOf(['pYear', YearOf(Param.Date), 'pMonth', MonthOf(Param.Date), 'pUNP', Data^.UNP, 'pBase', Ord(Param.Base)]));
    DM.qGetBuyCons.Open;
...
...
...
  InitqTbl(qTmp1, VarArrayOf(['UNP', aUNP, 'Firm', Ord(aF), 'Article', aArt, 'CountBuy', Val + R.x + R.y, 'Promo', 0, 'DateOp', Now]),
           'INSERT INTO acc (UNP, Firm, Article, CountBuy, Promo, DateOp) VALUES (:UNP, :Firm, :Article, :CountBuy, :Promo, :DateOp)');
  qTmp1.ExecSQL;

...
...
...
  InitqTbl(qHistory, VarArrayOf(['TimeOperation', Now, 'Base', Ord(Param.Base), 'UN', UN, 'TypeOperation', Ord(TypeHistory), 'BuyDate', IIF(BuyDate<>0, BuyDate, Now)]));
  qHistory.ExecSQL;

sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Re: Как не забыть порядок параметров

Сообщение stanilar » 10.04.2014 12:37:21

Mirage писал(а):Есть такие IDE, что иногда закрадывается подозрение, будто мысли они таки читают.


Мне один студент-дипломник, после знакомства с рассчетной программой, которую отдел разрабатывал и поддерживал лет 20 (все начиналось с TurboPascal), сказал что программа простая и ему в ней все понятно. Проект, изначально, был написан а процедурном стиле, потом переработан на Delphi7.
stanilar
постоялец
 
Сообщения: 289
Зарегистрирован: 09.03.2010 19:09:02

Re: Как не забыть порядок параметров

Сообщение Mirage » 10.04.2014 19:17:01

скалогрыз писал(а):не надо выучивать всё. Нужно выучить наиболее часто используемые... тот же Pos.


Это я и имел в виду. Наиболее часто используемые можно выучить, а с остальными будут проблемы.

скалогрыз писал(а):Так в этом и вопрос: что если обязательных полей много


Они будут в конструкторе. Все. Проблем нет. Даже без билдера нет. Билдер нужен, когда появляются опциональные параметры.
В очередной раз напомню, что билдером мы не решаем проблему "забывания порядка параметров".

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

И это
скалогрыз писал(а):Инлайнить всё подряд просто нехорошо и пагубно сказывается на размерах кода.


Слегка противоречат друг другу. Вы не находите?
Понятно ведь, что если правильно все заинлайнить, то в коде останутся только присваивания полям значений. Как в случае без билдера.

скалогрыз писал(а):Вообще-то очень даже глобальны. Почему.
1) это объект, и создание объекта это операции с динамической паматью и для экономии времени, обычно принято объекты переиспользовать. Т.е. логично создать 1 билдер, а потом его использовать чтобы пораждать много реализаций.
А иначе получается двойной расход на создание объекта: * сначала создай билдер * потом создай объект * потом билдер освободи.???
2) раз объект создан один раз, то руки чешутся не создавать билдеры для каждого потока, а надо. (К тому же, если билдеры нужны для создания immutable объектов, которые как-раз хороши для много поточности?!)


Тут два варианта:
1. Создать билдер и использовать его для создания одного и того же объекта много раз. Смысла создавать несколько раз один и тот же иммутабельный объект нет никакого, ибо одного хватит.
2. Создать билдер и использовать его для создания разных объектов. Тоже смысла нет, т.к. для этого нам придется билдер модифицировать. А мы ведь его используем как раз для того, чтобы избежать использования мутабельных объектов, да еще в многопоточном приложении.
Странно, что у Вас "логично" и "руки чешутся" делать то, что не имеет смысла.

скалогрыз писал(а):Реализацией самой функции.
Т.е. на тех же самых гарантиях, что и вызов "build()" в builder-е гарантирует инициализацию всех полей.


Чтобы дать те же самые гарантии, реализация функции должна быть весьма нетривиальной.

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


Задача билдера - создать объект. Как и куда он потом будет передаваться вообще не зависит от того, как он создан.

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


Можете развернуть мысль? А то набор слов какой-то.

скалогрыз писал(а):Почему, потому что ни один язык не предоставляет возможности описания immutable объектов. Вместо этого программист обязан, написать необходимые защитные методы.... ну да, и как итог написать билдеры :)


Не понял, где там такое написано. В Java, например, есть возможность описать immutable объект.

скалогрыз писал(а):Нужно заметить, что они не требуют синхронизации, потому что являются read-only.
Если два потока могут зависят от изменённых данных, immutable объекты внезапно приводят к ошибкам.
Т.к. либо не видят изменённых данных, либо каждый работает со своей копией данных.


Каких измененных данных? Если нужны изменяемые, разделяемые между потоками, данные, то никто не будет в качестве таких данных использовать immutable объекты.
Они как раз нужны, чтобы иметь гарантию того, что не будет случайного изменения данных, скажем, в каком-то из потоков. Что привело бы к труднообнаружимым ошибкам.

скалогрыз писал(а):Нужно заметить, что read-only подход можно использовать не вводя такого понятия как "immutable object" дабы себе мозг не загромождать :)


Immutable object это как раз один из способов реализации такого подхода.
А реализовывать его ручками не так просто, как может показаться.

скалогрыз писал(а):Код нужно писать так, чтобы его можно было понимать и изменять не имея под рукой удобной IDE.


Соглашусь, однако писать его лучше все же в удобной IDE.

скалогрыз писал(а):P.S: Интересный список!.Билдеры попадают под понятие "Полтергейст" :mrgreen:


Под это понятие обычно подпадают т.н. DTO-объекты, часто используемые при передаче данных, например, между БД или каким-нибудь API и классами предметной области. Да и не думаю что это прямо такой уж антипаттерн. Записи тогда тоже антипаттерн?

скалогрыз писал(а):А в паскале невозможно сделать immutable объект в принципе - с точки зрения потоковой безопасности!
Очень просто, как минимум один момент всегда нужно будет синхронизировать - это момент уничтожения объекта.


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

hinst писал(а):Скажи плз, что за фича в FPC с вызовом методов с именованными параметрами, про которую ты пишешь


Есть возможность перехватить вызов метода у OleVariant'a. Прочитать названия параметров и их значения и обработать как угодно.

stanilar писал(а):
Mirage писал(а):Есть такие IDE, что иногда закрадывается подозрение, будто мысли они таки читают.


Мне один студент-дипломник, после знакомства с рассчетной программой, которую отдел разрабатывал и поддерживал лет 20 (все начиналось с TurboPascal), сказал что программа простая и ему в ней все понятно. Проект, изначально, был написан а процедурном стиле, потом переработан на Delphi7.


Здорово, но причем тут IDE?
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Как не забыть порядок параметров

Сообщение скалогрыз » 10.04.2014 22:17:35

Mirage писал(а):Они будут в конструкторе. Все. Проблем нет. Даже без билдера нет. Билдер нужен, когда появляются опциональные параметры.
В очередной раз напомню, что билдером мы не решаем проблему "забывания порядка параметров".

Какое ограниченное применения получается для билдеров.
Только, если у объекта много не обязательных полей и мало обязательных.
И только если объект immutable.

Mirage писал(а):Это утверждение:
скалогрыз писал(а):Особенно если вызвов метода занимает больше времени от процессора чем тело самой функции.
А для билдера это очень свойственно, потому что кроме сохранения данных, ему ещё нужно вернуть ссылку на себя. Т.е. это как минимум две операции, вместо одной, + расход на вызвов самого метода - заполнение регистров и стэка.

И это
скалогрыз писал(а):Инлайнить всё подряд просто нехорошо и пагубно сказывается на размерах кода.


Слегка противоречат друг другу. Вы не находите?

Не нахожу.
Первое говорит о проблема медленного исполнения кода.
Второе говорит о проблеме неявного увеличения размера кода.

Mirage писал(а):Понятно ведь, что если правильно все заинлайнить, то в коде останутся только присваивания полям значений. Как в случае без билдера.

Если я могу достичь такого же результа и без билдера, зачем мне билдер нужен?

Mirage писал(а):Тут два варианта:
1. Создать билдер и использовать его для создания одного и того же объекта много раз. Смысла создавать несколько раз один и тот же иммутабельный объект нет никакого, ибо одного хватит.
2. Создать билдер и использовать его для создания разных объектов. Тоже смысла нет, т.к. для этого нам придется билдер модифицировать. А мы ведь его используем как раз для того, чтобы избежать использования мутабельных объектов, да еще в многопоточном приложении.

В коде ниже, один объект TStamp (по аналогии с хабр примером) печатается на 10 разных конвеерах (каждый контролируется своим потоком).
А целом по задаче, таких разных наклеечек у нас 100.
Напрашивается вопрос, нужен ли тут билдер? И есть ли контр-пример, когда без билдера ну не обойтись?

По алгоритму, видно, что проще создать билдер один раз, но как-бы нельзя, ибо "смысла нет"?!
Код: Выделить всё
var
  s: TStamp;
  sb: TStampBuilder;
  ...
  for i:=1 to 100 do begin
    sb:=TStampBuilder.Create;
    s:=sb.SetTitle( Name[i] ).setData( Data[i] ).setPrice( PriceList[i] ).build();
    for j:=1 to 10 do
      LaunchPrintingThread(s);
    sb.Free;
  end;


Mirage писал(а):Странно, что у Вас "логично" и "руки чешутся" делать то, что не имеет смысла.

Почему экономить на перераспределении памяти не имеет смысла?
Для меня переиспользование объектов - это логично.

скалогрыз писал(а):Реализацией самой функции.
Т.е. на тех же самых гарантиях, что и вызов "build()" в builder-е гарантирует инициализацию всех полей.


Mirage писал(а):Чтобы дать те же самые гарантии, реализация функции должна быть весьма нетривиальной.


Код: Выделить всё
function BuildStampWithSomeData(const Title, Data: string; Price: double): TStamp;
begin
  Result:=TStamp.Create;
  Result.Title:=Title;
  ...
end;

Весьма тривиально, атомарно, потоко-безопасно, данные размещаются в стеке (экономя на перераспределении).

Да, возможно передавать много параметров не красиво, сделаем, как это делали все прошлые десятилетия:
Код: Выделить всё
type
  TStampData = record
    title : string
    ....
  end;

function BuildStampWithMoreData(const data: TStampData): TStamp;
begin
  Result:=TStamp.Create;
  Result.Title:=data.Title;
  ...
end;

Опять же - весьма тривиально, атомарно, потоко-безопасно, данные размещаются в стеке (экономя на перераспределении).
Кроме того, написать и использовать функцию - проще, чем билдер.
Есть ли что-нибудь, что то функцию не гарантируют, что гарантирует билдер?

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

Можете развернуть мысль? А то набор слов какой-то.


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

:D :D :D Спасибо за развёртывание мысли! Оказывается это не было набором слов :D :D :D :D

Даже приведу пример песвдокода - TStamp немутабельный объект (очевидно).
Каждый из потков печати использует TStamp только для чтения, без каких-либо синхронизаций.
Код: Выделить всё
var
  s: TStamp;
  ...
  for i:=1 to 100 do begin
    s:=TStamp.Create;
    s.Title:=Name[i];
    s.Data:=data[i];
    s.Price:=Price[i];
    for j:=1 to 10 do
      LaunchPrintingThread(s);
    AddToReleaseListOnceThreadsAreDone(s);
  end;

procedure PrintingThread(stamp: TStamp);
begin
  while not EofOfPaper do begin
    Print(stamp.Title);
    Print(stamp.Data);
    Print(stamp.Price);
  end;
end;

И зачем мне TStampBuilder (лишнего кода написать?), когда я вполне справился с TStamp?

Но продолжая тему алгоритмов:
Mirage писал(а):Они как раз нужны, чтобы иметь гарантию того, что не будет случайного изменения данных, скажем, в каком-то из потоков. Что привело бы к труднообнаружимым ошибкам.

Не изменяйте данные "случайно". Если приходится использовать код, над которым нет контроля (что было бы странно), то лучше сделать копию явно, и отдать ему эту копию для работы.


Mirage писал(а):Не понял, где там такое написано. В Java, например, есть возможность описать immutable объект.

а ты не путаешь с понятием Immutable (Final) Class? ;) потому что это разные вещи.
Mirage писал(а):Immutable object это как раз один из способов реализации такого подхода.
А реализовывать его ручками не так просто, как может показаться.

и как же его сделать не ручками?
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Как не забыть порядок параметров

Сообщение hinst » 10.04.2014 22:22:02

Какая-нибудь бажная функция в библиотеке, которую даже не вы писали начнёт делать вычисления с указателями, и запишет в рандомную область памяти рандомный мусор и перезапишет ваш immutable-объект

Добавлено спустя 1 минуту 45 секунд:
И буит Access Violation (ノಠ益ಠ)ノ彡┻━┻ FFFUUU
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Как не забыть порядок параметров

Сообщение скалогрыз » 10.04.2014 22:50:20

hinst писал(а):Какая-нибудь бажная функция в библиотеке, которую даже не вы писали начнёт делать вычисления с указателями, и запишет в рандомную область памяти рандомный мусор и перезапишет ваш immutable-объект

Добавлено спустя 1 минуту 45 секунд:
И буит Access Violation (ノಠ益ಠ)ノ彡┻━┻ FFFUUU

это в Jave-то? :mrgreen:
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Как не забыть порядок параметров

Сообщение hinst » 10.04.2014 23:08:29

Как это ни пичально, это и в жабе тоже. Жаба использует нативные библиотеки, и функциям из dll и .so-шников ничто вроде бы не помешает писать в адресное пространство JVM, загрузившей их, да и сама JVM бажная, у людей иногда она падает
Если программа использует нативные библиотеки по минимуму, то это как бы минимизирует риск, но он всё равно есть

Добавлено спустя 1 минуту 9 секунд:
а мне практика подсказывает что масштабные программы нативные библиотеки используют в весомых количествах

Добавлено спустя 19 секунд:
всякие там подключалки к БД, рендеры PDF, GUI и прочие
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Как не забыть порядок параметров

Сообщение Mirage » 11.04.2014 19:45:39

скалогрыз писал(а):Первое говорит о проблема медленного исполнения кода.


Да, потому что "вызвов метода занимает больше времени от процессора чем тело самой функции". Что возможно, если тело функции очень мало. Но тогда её инлайнинг не увеличит размер кода, а только увеличит скорость.

скалогрыз писал(а):Если я могу достичь такого же результа и без билдера, зачем мне билдер нужен?


Билдер это в общем-то просто объект. Можно его заполнять (необязательные поля) обычными присваиваниями. Просто fluent-style выглядит красивее. Но это дело вкуса. Плюс иногда бывает группа параметров, по отдельности не имеющих смысла.
Разница в том, что затем экземпляр билдера передается в конструктор immutable объекта.

скалогрыз писал(а):В коде ниже, один объект TStamp (по аналогии с хабр примером) печатается на 10 разных конвеерах (каждый контролируется своим потоком).
А целом по задаче, таких разных наклеечек у нас 100.
Напрашивается вопрос, нужен ли тут билдер? И есть ли контр-пример, когда без билдера ну не обойтись?


Перво-наперво надо сделать допущение, что в FPC есть immutable объекты. Иначе смысла использовать билдер нет никакого. Думаю, это понятно.

скалогрыз писал(а):По алгоритму, видно, что проще создать билдер один раз, но как-бы нельзя, ибо "смысла нет"?!


Переиспользовать билдер это экономить на спичках. Если бы создание объектов являлось узким местом, то оно также было бы вынесено в разные потоки. И переиспользование билдера было бы бессмысленно по описанным мной причинам. А так оно бессмысленно потому что экономит там где не нужно.
Чтобы не было такого соблазна, то во-первых не должно быть возможности создать билдер отдельно от его основного класса, только через специальный метод:
Код: Выделить всё
TImmutableClass.getBuilder()

Ну и в методе build() он сам себя освобождает.
Теперь не только бессмысленно, но и нельзя.

скалогрыз писал(а):Для меня переиспользование объектов - это логично.


Переиспользование повышает вероятность ошибок, т.к. вносит дополнительную зависимость от того, что было в объекте ранее. Буквально вчера по работе исправлял очередную такую ошибку, где переиспользовался объект, но одно поле обнулить забыли.

скалогрыз писал(а):
Код: Выделить всё
function BuildStampWithSomeData(const Title, Data: string; Price: double): TStamp;
begin
  Result:=TStamp.Create;
  Result.Title:=Title;
  ...
end;

Весьма тривиально, атомарно, потоко-безопасно, данные размещаются в стеке (экономя на перераспределении).


Вынужден спросить: Вы занимались разработкой многопоточных программ?
Это не атомарно и не потокобезопасно.
Например вызываем stamp := BuildStampWithSomeData(blabla...);
Процессор (или компилятор) переставляют инструкции таким образом, что сперва идет Result := TStamp.Create(), затем stamp := Result, а затем уже все остальное. Имеет право, между прочим.
Вот после stamp := Result первый поток засыпает, просыпается второй и спокойно использует stamp, где не инициализировано ни одно поле.
А потом просыпается первый поток и дописывает поля stamp'a. Поверх того, что уже успел записать туда второй поток.
Такую ошибку можно долго искать.
Это если одно ядро. На нескольких все еще печальнее.

скалогрыз писал(а):Есть ли что-нибудь, что то функцию не гарантируют, что гарантирует билдер?


Билдер сам по себе ничего не гарантирует, кроме передачи всех параметров прямо в конструктор.
Однако, если объект immutable и это поддерживается компилятором, то есть гарантия, что все поля по выходу из конструктора для всех потоков имеют именно то значение, какое присвоено в конструкторе.
В Java это гарантируется для всех final полей класса.

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

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

:D :D :D Спасибо за развёртывание мысли! Оказывается это не было набором слов :D :D :D :D


Это вообще-то не алгоритмическое решение проблемы синхронизации, а архитектурное. И возможно оно далеко не всегда.
С уничтожением объектов проще, потому как оно обычно в конце чего-то происходит. Либо можно подвинуть в конец.
А в общем случае проблема синхронизации так и близко не решается.

скалогрыз писал(а):Даже приведу пример песвдокода - TStamp немутабельный объект (очевидно).
[поскипан некорректный код]
И зачем мне TStampBuilder (лишнего кода написать?), когда я вполне справился с TStamp?


Если не волнует, что printingThread может получить неинициализированный объект и, соответственно, напечатать ерунду, то не нужен.

скалогрыз писал(а):Не изменяйте данные "случайно".


При групповой разработке больших проектов довольно трудно понять, что менять можно, а что нет. Immutable объект точно нельзя.
Доказывать, что immutable объекты помогают избежать ошибок более не буду. Это и без меня неплохо обосновано.

скалогрыз писал(а):а ты не путаешь с понятием Immutable (Final) Class? ;) потому что это разные вещи.


final класс просто нерасширяемый класс. Никакой он еще не immutable.

скалогрыз писал(а):и как же его сделать не ручками?


Объявить все поля как final. Сам класс, на всякий случай, тоже final.
Это потребует инициализации всех полей либо сразу, либо в конструкторе. Но даст вышеописанную гарантию.
Гарантия дается в рамках т.н. Java memory model, т.е. модели памяти языка.
Она еще много чего гарантирует, причем независимо от железа.
Любому языку, претендующему на кроссплатформенность, иметь модель памяти крайне желательно.
Даже C++ в версии C++11 ею наконец обзавёлся.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Как не забыть порядок параметров

Сообщение скалогрыз » 11.04.2014 21:35:49

Mirage писал(а):Билдер это в общем-то просто объект. Можно его заполнять (необязательные поля) обычными присваиваниями.
Просто fluent-style выглядит красивее. Но это дело вкуса. Плюс иногда бывает группа параметров, по отдельности не имеющих смысла.

Про fluent-style - писать обёртку ради "красивее"? Fluent-style вообще в паскале применяется не так уж и часто - функция может и nil вернуть.
А что ещё хуже:
Код: Выделить всё
procedure TSomeEpicBuilder.SetVariable(a: Integer);
begin
  fa:=a;
  // а вот Result:=Self програмист и забыл.
end;

может слегка порушить создание объекта.

Mirage писал(а):Перво-наперво надо сделать допущение, что в FPC есть immutable объекты. Иначе смысла использовать билдер нет никакого. Думаю, это понятно.

Пожалуйста, весьма Immutable!
Код: Выделить всё
type
  TImmutableSomething = class()
  private
    fYouCantChangeMe: TType;
  public
    property YouCantChangeMe: TType read fYouCantChangeMe;
  end;



Mirage писал(а):Разница в том, что затем экземпляр билдера передается в конструктор immutable объекта.
...
Переиспользовать билдер это экономить на спичках. Если бы создание объектов являлось узким местом, то оно также было бы вынесено в разные потоки.
И переиспользование билдера было бы бессмысленно по описанным мной причинам.
А так оно бессмысленно потому что экономит там где не нужно.
Чтобы не было такого соблазна, то во-первых не должно быть возможности создать билдер отдельно от его основного класса,
только через специальный метод:
Код: Выделить всё
TImmutableClass.getBuilder()

Ну и в методе build() он сам себя освобождает.
Теперь не только бессмысленно, но и нельзя.

Я же говорю - очень много инфраструктуры.
Что ещё хуже, "builder" по-своей логике служебный класс (т.к. он используется только для порождения новых классов), превращается в коренной класс,
т.к. без него "immutable object" не создастся, ибо должен передаваться в конструктор.

Mirage писал(а):Переиспользование повышает вероятность ошибок, т.к. вносит дополнительную зависимость от того, что было в объекте ранее.
Буквально вчера по работе исправлял очередную такую ошибку, где переиспользовался объект, но одно поле обнулить забыли.

Добавили поле, а метод Clear() не обновили. Ну что поделать - бывает.
Я бы предложил переписать всё на пересоздание объекта (вместо очищения).
Возможно, в итоге придётся вместо исправляния ошибок "не очищения", заниматся оптимизацей (вeрнувшись к переиспользованию объектов :D ).

А теперь посмотрим на туже проблему с точки зрения билдера.
Добавили новое поле в базовый класс, а вот код build() не поменяли, или даже метода не добавили для инициализации этого поля.
И оно приняло значение 0, хотя по-умолчанию, должна иметь другое значение.
Наличие билдера проблему не решает никак.


Mirage писал(а):Вынужден спросить: Вы занимались разработкой многопоточных программ?
Это не атомарно и не потокобезопасно.
Например вызываем stamp := BuildStampWithSomeData(blabla...);
Процессор (или компилятор) переставляют инструкции таким образом, что сперва идет Result := TStamp.Create(), затем stamp := Result, а затем уже все остальное. Имеет право, между прочим.
Вот после stamp := Result первый поток засыпает, просыпается второй и спокойно использует stamp, где не инициализировано ни одно поле.
А потом просыпается первый поток и дописывает поля stamp'a. Поверх того, что уже успел записать туда второй поток.
Такую ошибку можно долго искать.
Это если одно ядро. На нескольких все еще печальнее.

O.o

Отвечу на первый вопрос: да - занимаюсь разработкой многопоточных программ.
Вообще не понял к чему здесь:
Mirage писал(а):Процессор (или компилятор) переставляют инструкции таким образом, что сперва идет Result := TStamp.Create(), затем stamp := Result, а затем уже все остальное. Имеет право, между прочим.
Вот после stamp := Result первый поток засыпает, просыпается второй и спокойно использует stamp

[поскипан некорректный код]

Если не волнует, что printingThread может получить неинициализированный объект и, соответственно, напечатать ерунду, то не нужен.

Для начала:
Локальные данные располагаются в стеке самого потока, т.е. если поток №1 и поток №2 выполняют один и тот же код.
Код: Выделить всё
procedure SomeProc;
var
  stamp: TStamp;
begin
  ..
  stamp := BuildStampWithSomeData(blabla...)


Так у каждого "stamp" и "Result" будет свой - и никаких проблем нет.

Но к примеру, который я привёл, это вообще не имеет отношение!
Вызов BuildStampWithSomeData выполняется главным потоком.
Соответственно объект будет инициализирован перед, запуском потоков-исполнителей.
Просто потому что запуск потоков-исполнителей так же выполняется главным потоком.

Если ты хочешь сказать, что основной поток внезапно перепрыгнет
со строчки
Код: Выделить всё
  stamp:=BuildStampWithSomeData

на
Код: Выделить всё
  for j:=1 to 10 do
    LaunchPrintingThread(stamp)

и при этом исполнение BuildStampWithSomeData не завершилось, то я требую доказательств в виде примера.
(...этакие фантомные goto операции... )

Mirage писал(а):Билдер сам по себе ничего не гарантирует, кроме передачи всех параметров прямо в конструктор.
Однако, если объект immutable и это поддерживается компилятором, то есть гарантия, что все поля по выходу из конструктора
для всех потоков имеют именно то значение, какое присвоено в конструкторе.
В Java это гарантируется для всех final полей класса.

Подумай ещё раз.
Final поля выполняют проверку во время компиляции, но не во время исполнения программы.
К потокобезопасности вообще никакого отношения не имеют.
(там же приведён пример, того что для "сложных" классов, понадобится писать дополнительные immutable обёртки - и для них тоже свои билдеры :D
Так вот спички скалдываются в горы спичек :D но стоит ли экономить? )

Mirage писал(а):Это вообще-то не алгоритмическое решение проблемы синхронизации, а архитектурное. И возможно оно далеко не всегда.
...
При групповой разработке больших проектов довольно трудно понять, что менять можно, а что нет.

При групповой разработке очень помогает документация (на которую нет ни времени, ни сил - ещё бы!).
Ещё больше документация помогает реализовывать архитектурные решения.
Но это к теме никакого отношения не имеет.

Mirage писал(а):Объявить все поля как final. Сам класс, на всякий случай, тоже final.

О чём я и говорю, что на каждый "mutable" класс понадобится написать "immutable" а к нему ещё и "builder" :D
Написанный код увеличится втрое, скомпилированный вдвое. Каких-то дополнительных улучшений не будет. Зачем?

На самом деле, похоже что восхваляемые "immutable" объекты это просто "общая-копия" данных.
Сделай копию и используй её спокойно во всех потоках сколько влезет (о синхронизации можно и не думать).

Почему бы вместо builder-а просто не использовать соответствующий рабочий класс.
С сохранением логической порядка, где ImmutableObject это служебный класс и зависит от основного.
Код: Выделить всё
type
  TMutableObject = class(TObject)
  public
    Data : Integer;
  end;

type
  TImmutableObject = class(TObject)
  private
    fData: integer;
  public
    constructor Create(amutable: TMutableObject); // конструктор копирует нужные данные
    property Data : Integer read fData;
  end;

Все дела! нахрена спец-билдеры c fluent-style и build() методом? непонятно!

На самом деле понятно, но я причины не буду озвучивать, ибо это сугубо моё личное мнение в сторону автора книжки/статьи про билдеры, никак с технической стороной вопроса не связанные.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Как не забыть порядок параметров

Сообщение Mirage » 12.04.2014 14:56:51

скалогрыз писал(а): // а вот Result:=Self програмист и забыл.
может слегка порушить создание объекта.


Это упущение синтаксиса конкретного языка. Если подпрограмма объявлена как функция, то обязана возвращать результат.

скалогрыз писал(а):Я же говорю - очень много инфраструктуры.
Что ещё хуже, "builder" по-своей логике служебный класс (т.к. он используется только для порождения новых классов), превращается в коренной класс,
т.к. без него "immutable object" не создастся, ибо должен передаваться в конструктор.


Билдер в Java обычно объявляется как внутренний класс. Можно только получить экземпляр через статический метод его родительского класса.

скалогрыз писал(а):Я бы предложил переписать всё на пересоздание объекта (вместо очищения).
Возможно, в итоге придётся вместо исправляния ошибок "не очищения", заниматся оптимизацей (вeрнувшись к переиспользованию объектов :D ).


Лучше переписать сразу на immutable объектах.
Насчет необходимости оптимизации - крайне маловероятно. Переиспользование объектов не дает заметного выигрыша, за исключением особых случаев, когда приходится создавать очень много объектов в секунду.
Но это особые и крайне редкие случаи.

скалогрыз писал(а):Добавили новое поле в базовый класс, а вот код build() не поменяли, или даже метода не добавили для инициализации этого поля.
И оно приняло значение 0, хотя по-умолчанию, должна иметь другое значение.
Наличие билдера проблему не решает никак.


У immutable класса новое поле в конструкторе должно задаваться, т.к. иначе код не скомпилируется.
Значит придется добавлять новое поле и в билдер и метод build() менять, чтобы передать новое поле.
Можно забыть создать метод для инициализации нового поля в билдере, но такая ошибка быстро выплывет, т.к. очевидно, захочется новое поле как-то задавать.
Да и нормальная IDE подсветит варнингом приватное поле, которое не имеет кода, модифицирующего его значение.

скалогрыз писал(а):Отвечу на первый вопрос: да - занимаюсь разработкой многопоточных программ.


Как же вы это делаете, не имея представления об out of order execution и его влиянии на многопоточные программы?
Почитайте хотя бы это:
http://en.wikipedia.org/wiki/Memory_barrier

скалогрыз писал(а):Вызов BuildStampWithSomeData выполняется главным потоком.
Соответственно объект будет инициализирован перед, запуском потоков-исполнителей.
Просто потому что запуск потоков-исполнителей так же выполняется главным потоком.


Другие потоки совершенно не обязательно видят то же, что и главный.
Не только из-за выполнения инструкций не по порядку, но и из-за других оптимизаций. Например, какое-то поле помещено в регистр и там происходит его модификация, пока в какой-то, возможно неблизкий, момент времени не будет сброшено в память. Код другого потока ничего об этом не знает. Он это поле из памяти читать будет.

скалогрыз писал(а):и при этом исполнение BuildStampWithSomeData не завершилось, то я требую доказательств в виде примера.
(...этакие фантомные goto операции... )


Доказательств существования проблем с видимостью модификаций, сделанных одним потоком, в других потоках? Вы серьезно?

скалогрыз писал(а):Final поля выполняют проверку во время компиляции, но не во время исполнения программы.
К потокобезопасности вообще никакого отношения не имеют.


Лучше не писать о вещах, в которых не разбираетесь.
Я не зря писал о JMM. Именно модель памяти дает гарантии потокобезопасности immutable классов.
http://docs.oracle.com/javase/specs/jls ... ls-17.html

скалогрыз писал(а):(там же приведён пример, того что для "сложных" классов, понадобится писать дополнительные immutable обёртки - и для них тоже свои билдеры :D


Где там такой пример?

скалогрыз писал(а):Ещё больше документация помогает реализовывать архитектурные решения.


Скорее хорошая архитектура позволяет писать меньше документации.

скалогрыз писал(а):О чём я и говорю, что на каждый "mutable" класс понадобится написать "immutable" а к нему ещё и "builder" :D
Написанный код увеличится втрое, скомпилированный вдвое. Каких-то дополнительных улучшений не будет. Зачем?


Что-то у Вас объекты все размножаются и размножаются.
Теперь появился какой-то mutable, для которого нужен immutable.

Речь шла о том, чтобы использовать immutable объекты в многопоточной среде.
Для этого нужен ровно один объект - этот самый immutable.
В редких случаях, когда много необязательных параметров, бывает полезен вспомогательный объект-билдер.
Вы пытаетесь из этого редкого случая сделать трагедию, непонятно зачем.

Плюс Вам не нравятся immutable объекты, хотя Вы не понимаете что это вообще такое. Скорее всего, поэтому и не нравятся.
Но можно все, что не понятно, объявить заговором и модой. И активно не любить. Так многие и делают.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Как не забыть порядок параметров

Сообщение скалогрыз » 12.04.2014 22:34:38

Mirage писал(а):
скалогрыз писал(а):Я бы предложил переписать всё на пересоздание объекта (вместо очищения).
Возможно, в итоге придётся вместо исправляния ошибок "не очищения", заниматся оптимизацей (вeрнувшись к переиспользованию объектов :D ).

Лучше переписать сразу на immutable объектах.

неудобно, наверное, работать с объектом, в котором ничего нельзя поменять?

Mirage писал(а):Переиспользование объектов не дает заметного выигрыша, за исключением особых случаев, когда приходится создавать очень много объектов в секунду.
Но это особые и крайне редкие случаи.

Соглашусь - Игры и GUI приложения случаи крайне редкие.

Mirage писал(а):
скалогрыз писал(а):Отвечу на первый вопрос: да - занимаюсь разработкой многопоточных программ.

Доказательств существования проблем с видимостью модификаций, сделанных одним потоком, в других потоках? Вы серьезно?

Доказательство, того, что приведённый мною ранее код неправильный и работать не будет.

Облегчу твою задачу, Мираж. Программу я написал (прикладываю к сообщению)
Смело проверяй! ищи ошибки, с точки зрения синхронизации.
Так же, хотелось бы увидеть тот случай, когда хотя бы идин из потоков начнёт работу до заврешения BuildStampWithSomeData, и как итог получит не инициализированные объект (а то и объекта не получит).


Mirage писал(а):Лучше не писать о вещах, в которых не разбираетесь.
Я не зря писал о JMM. Именно модель памяти дает гарантии потокобезопасности immutable классов.
http://docs.oracle.com/javase/specs/jls ... ls-17.html

Со своим уставом в чужой монастырь? ;) Ладно.

Напомню.
скалогрыз писал(а):Final поля выполняют проверку во время компиляции, но не во время исполнения программы.
К потокобезопасности вообще никакого отношения не имеют.

Читаем:
Java Specs 17.5 писал(а):The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields.

Действительно, нужно позаботится о синхронизации передачи ссылки на объект (что в принципе очевидно), т.к. само поле никакой защиты не предоставит.

Mirage писал(а):
скалогрыз писал(а):(там же приведён пример, того что для "сложных" классов, понадобится писать дополнительные immutable обёртки - и для них тоже свои билдеры :D

Где там такой пример?


Wikipedia писал(а):To illustrate that finality doesn't guarantee immutability: suppose we replace the three position variables with a single one:

public final Position pos;

where pos is an object with three properties pos.x, pos.y and pos.z. Then pos cannot be assigned to, but the three properties can, unless they are final themselves.

Вот так. Нужно написать ImmutablePosition и для него билдер (соответственно) ;)

Mirage писал(а):
скалогрыз писал(а):О чём я и говорю, что на каждый "mutable" класс понадобится написать "immutable" а к нему ещё и "builder" :D
Написанный код увеличится втрое, скомпилированный вдвое. Каких-то дополнительных улучшений не будет. Зачем?


Что-то у Вас объекты все размножаются и размножаются.
Теперь появился какой-то mutable, для которого нужен immutable.

Mutable это рабочий класс, (как скажем Position, упомянутый в примере википедии), данные которого можно менять.
Естественно, называтся "mutable" он не будет.
Для полноценной реализации Immutable-объектов, ему понадобится Immutable пара (для поточного использования)- ImmutablePosition.

Ладно. Читаем Java устав дальше:
Java Specs: 17.5.3. Subsequent Modification of final Fields писал(а): Final fields can be changed via reflection and other implementation-dependent means.

О.о. коту под хвост. Хитрые программист начнут втихушечку переписывать значение "ручками" через reflection :) Компилятор же за ними теперь не уследит!

Mirage писал(а):Как же вы это делаете, не имея представления об out of order execution и его влиянии на многопоточные программы?

Другие потоки совершенно не обязательно видят то же, что и главный.
Не только из-за выполнения инструкций не по порядку, но и из-за других оптимизаций. Например, какое-то поле помещено в регистр и там происходит его модификация, пока в какой-то, возможно неблизкий, момент времени не будет сброшено в память. Код другого потока ничего об этом не знает. Он это поле из памяти читать будет.

Читаем устав:
Java Specs: 17.5.3. Subsequent Modification of final Fields писал(а):The detailed semantics of final fields are somewhat different from those of normal fields. In particular, compilers have a great deal of freedom to move reads of final fields across synchronization barriers and calls to arbitrary or unknown methods.

Как следствие, приведённый в уставе пример с "Aggressive Optimization of final Fields", конечно, из области извращений.
Но ведь кто знает, что там люди могут понаписать, а как итог
Java Specs: 17.5.3. Subsequent Modification of final Fields писал(а):..., the compiler is allowed to reorder the reads of x and the call to g freely. Thus, new A().f() could return -1, 0, or 1.

Один и тот же код компилируется по разному, в зависимости от настроения комплиятора.

А вот в Паскале (опять же пока-что) нету ключевых слов указывающих на межпоточное взаимодействие переменных, таких как volitle в Си, или тот же final в Jave.
По-этому, ВСЯ синхронизация ложится на хрупкие плечи программиста, что имеет свои явные плюсы, т.к. код работает предсказуемо.

Mirage писал(а):Речь шла о том, чтобы использовать immutable объекты в многопоточной среде.
Для этого нужен ровно один объект - этот самый immutable.
В редких случаях, когда много необязательных параметров, бывает полезен вспомогательный объект-билдер.
Вы пытаетесь из этого редкого случая сделать трагедию, непонятно зачем.

Плюс Вам не нравятся immutable объекты, хотя Вы не понимаете что это вообще такое. Скорее всего, поэтому и не нравятся.
Но можно все, что не понятно, объявить заговором и модой. И активно не любить. Так многие и делают.

Ну конечно я не понимаю.
Мне говорят, что писать мало кода - это плохо, нужно писать много (и муторно) дополнительного кода, а в чём улучшение не говорят, но ссылаются на статью на модном сайте, перевода модного автора.
Улучшение-то в чём? Безопаснее? вовсе нет.
---
Повторюсь, програмку я приложил 129 строк (хотел уместится в 100, да не смог).
Ищите ошибки синхронизации (их не может не быть)
Особенно интересует как
Mirage писал(а):...printingThread может получить неинициализированный объект и, соответственно, напечатать ерунду...

Предлагаю даже переписать его и заменить использование функции на Builder класс!
У вас нет необходимых прав для просмотра вложений в этом сообщении.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Пред.След.

Вернуться в Разное

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 19

Рейтинг@Mail.ru