пятница, 31 января 2014 г.

Скорее "для себя". Классы в скриптовой машине

Классы в скриптовой машине.

Вот тут - http://programmingmindstream.blogspot.ru/2014/01/blog-post_9030.html я писал "абстрактно", теперь напишу "конкретно"

Определение класса:

class TPoint

 INTEGER VAR X
 INTEGER VAR Y

 BOOLEAN FUNCTION Compare
  TPoint IN anOther
  Result := ( Self . X = anOther . X ) AND ( Self . Y = anOther . Y )
 ; // Compare

; // TPoint

Его использование:

TPoint VAR A := new TPoint
  A . X := 10
  A . Y := 20

TPoint VAR B := new TPoint
  B . X := 100
  B . Y := 200

A . Compare B WriteLn
 // - будет напечатано false

Как это "устроено изнутри":

[:] .
 // Определяем оператор .
 // [:] - означает, что определяется слово выполняемое при компиляции

 OBJECT VAR l_LeftParam := LastCompiledWord
 // - получаем слово, которое было скомпилировано перед вызовом нашего

 STRING VAR l_FieldName := NextToken
 // - выбираем следующий токен из входного потока

 ASSERT ( l_LeftParam ClassType HasMember l_FieldName Cat [ 'Класс не имеет члена: ' l_FieldName ] )
 // - проверяем, что на классе есть член с указанным именем

 OBJECT VAR l_Field := ( l_LeftParam ClassType GetMember l_FieldName )
 // - берём описатель члена класса

 CompileWord l_FieldName
 // - компилируем имя поля

 if ( l_Field IsVar ) then
 begin
  if ( NextToken = ':=' ) then
  begin
   // - это оператор присваивания
   OBJECT VAR l_ValueCode := CompileNextWord
   // - компилируем код ОДНОГО слова справа от нас
   CompileWord l_ValueCode
   // - копилируем код значения
   CompileWord @ SetFieldValue
   // - компилируем код установки значения
  end
  else
  begin
   UngetToken
   // - возвращаем токен во входной поток ибо он нам "не подошёл"
   CompileWord @ GetFieldValue
   // - компилируем код установки значения
  end
 end
 else
 if ( l_Field IsMethod ) then
 begin
  INTEGER VAR l_RightParamsCount := ( l_Field RightParamCount )
  // - получаем число "правых" параметров классового метода
  ARRAY VAR l_ParamsCode := [ l_RightParamsCount LOOP CompileNextWord ]
  // - компилируем l_RightParamsCount слов за нами и получаем их код в качестве массива
  CompileWord l_ParamsCode
  // - компилируем код параметров
  CompileWord @ Call
  // - компилируем функцию вызова метода
 end
 else
  ASSERT ( false 'Непонятный тип члена класса' )
; // .

Т. е. код:

  B . X := 100
  B . Y := 200
 A . Compare B WriteLn

Разворачивается в такой:

  B 'X' @ ( 100 ) SetFieldValue
  B 'Y' @ ( 200 ) SetFieldValue
 A 'Compare' [ B ] Call  WriteLn

А код:

 BOOLEAN FUNCTION Compare
  TPoint IN anOther
  Result := ( Self . X = anOther . X ) AND ( Self . Y = anOther . Y )
 ; // Compare

Разворачивается в такой:

 BOOLEAN FUNCTION Compare
  TPoint IN anOther
  Result := ( ( Self 'X' GetFieldValue ) = ( anOther 'X' GetFieldValue ) ) AND ( ( Self 'Y' GetFieldValue ) = ( anOther 'Y' GetFieldValue ) )
 ; // Compare

Дальше наверное надо описать как выглядят GetFieldValue, SetFieldValue и Call.

А также - как выглядит new.

Ну и конечно это всё - "навскидку". Можно тут оптимизировать - уходя от ИМЁН членов в реально скомпилированном коде.

Но там "не всё так просто".

Я ещё про VIRTUAL и OVERRIDE не написал.

GetFieldValue и SetFieldValue на самом деле выглядят просто:

: GetFieldValue
 OBJECT IN anInstance
 STRING IN aFieldName
 anInstance GetMember aFieldName DO
 // - берём ссылку на член класса и выполняем её
; // GetFieldValue

: SetFieldValue
 OBJECT IN anInstance
 STRING IN aFieldName
 OBJECT IN aValue
 anInstance GetMember aFieldName ^:= ( aValue DO )
 // - берём ссылку на член класса и прописываем в неё вычисленное значение aValue
; // GetFieldValue

Call тоже не выглядит уж очень сложным:

: Call
 OBJECT IN anInstance
 STRING IN aMethodName
 ARRAY IN aParam
 anInstance
 // - кладём ссылку на экземпляр на стек
 aParam ITERATE ( IN aParam aParam DO )
 // - вычисляем параметры и кладём их на стек
 anInstance GetMember aMethodName DO
 // - берём ссылку на член класса и выполняем её
; // GetFieldValue

Сложнее всего с new...

На самом деле тут используется "создание по образцу" (или по прототипу):

OBJECT WordWorker new
 ^ OBJECT IN aClass
 Result := ( class:TCompiledWord .Create )
 // - создаём РЕАЛЬНЫЙ класс приложения - TCompiledWord
 ARRAY VAR l_Members := aClass MembersIterator
 for l_Members ( 
  OBJECT IN aMember
  if ( aMember IsVar ) then
  begin
   Result -> ( aMember Name )
   // - создаём ссылку на НОВУЮ переменную
   ^ := ( aMember DO )
   // - инициализируем её значением по-умолчанию
  end
 )
; // new

Как выглядит .Create? Вот он как раз - "зашит в аксиоматике скриптовой машины".

Теперь как выглядят HasMember и GetMember:

BOOLEAN FUNCTION HasMember
 OBJECT IN aClass
 ^ STRING IN aMemberName
 Result := false
 for ( aClass MembersIterator ) (
  OBJECT IN aMember
  if ( aMember WordName = ( aMemberName DO ) ) then
  begin
   Result := true
   break
  end
 )
; // HasMember

OBJECT FUNCTION GetMember
 OBJECT IN aClass
 ^ STRING IN aMemberName
 Result := nil
 for ( aClass MembersIterator ) (
  OBJECT IN aMember
  if ( aMember WordName = ( aMemberName DO ) ) then
  begin
   Result := aMember
   break
  end
 )
; // GetMember

Теперь как выглядит оператор ->:

OBJECT FUNCTION ->
 OBJECT IN aClass
 ^ STRING IN aMemberName
 Result := nil
 for ( aClass MembersIterator ) (
  OBJECT IN aMember
  if ( aMember WordName = ( aMemberName DO ) ) then
  begin
   Result := aMember
   break
  end
 )
 Result := ( aClass AddVar aMemberName )
; // GetMember

Как выглядит AddVar? Вот он как раз - "зашит в аксиоматике скриптовой машины".

Про тесты ещё

Я когда-то писал об атомарных тестах и "комплексных тестах".

Попробую пояснить "разницу"...

Я сейчас работаю над одним БОЛЬШИМ куском проекта (ов).

Над "кодогенерацией из модели" в "целевые языки".

Там есть "комплексные" тесты, которые "грузят ВСЮ большую модель" и "как-то" её трансформируют.

И эти тесты служат - "дымовым анализатором".

Если они сломались, то значит - "что-то пошло не так".

Так о чём речь?

Эти "комплексные тесты" - сломались и показали ОШИБКУ. Уже - ПОЛ-ДЕЛА. Но!

Что с этим делать?

"Комплексные тесты" - продолжительные по времени, да и "отлаживать их тяжело".

Вот тут на помощь приходят "атомарные тесты".

Которые - "очень маленькие". Буквально "две три строки".

Но которые тестируют примитивы "грамматики целевого языка".

Что я делаю?

Я сначала запускаю "атомарные тесты" и смотрю, что "в них ничего не сломалось".

Потом я запускаю - "комплексные тесты" и смотрю - "а не сломалось ли что в них".

Если "сломалось", то я вычленяю проблему и пишу "атомарный тест".

ЕЩЁ ОДИН.

И "отлаживаюсь" на комплекте "атомарных тестов".

Которые "проходят за микросекунды".

Входные и выходные данные я для них придумываю "из головы".

Когда я отладился на "атомарных тестах" - я опять пускаю "комплексные тесты".

Ну и процесс - ИТЕРАТИВНЫЙ.

И "по ходу пьесы набирается набор "атомарных тестов", которые позволяют "всё реже и реже" пускать "комплексные тесты"".

Как-то так...

"Комплексные тесты" - порождают атомарные, а "атомарные" - валидируют "комплексные".

четверг, 30 января 2014 г.

О коммуникациях и "передаче знаний"

По мотивам поста - http://programmingmindstream.blogspot.ru/2014/01/blog-post_25.html

Ну и и обсуждения к нему.

Приведу для начала "картинку", которую мне прислали:

Что хочу сказать?

Во первых процитирую сам себя:

"к вопросу о "пошёл нахрен"...

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

и ОБЫЧНО люди - сами объяснят, что очень здорово в плане коммуникаций и "передачи знаний"

а вот если человек говорит - "объяснить" - тогда объясняю детали"

Почему я так делаю? Не потому, что "забыл" или "лень объяснять детали".

НАПРОТИВ - всегда НЕ ЛЕНЬ.

Но! Встаёт вопрос - а надо ли вываливать на человека детали, которые ему не нужны?

Вообще говоря - "не надо".

А если я ему "буду объяснять", то скорее всего - "я ему эти детали ВЫВАЛЮ".

А вот "если он мне объяснит", то скорее всего этих деталей можно будет избежать.

Конечно если он "в своём объяснении" упускает "ВАЖНЫЕ ДЕТАЛИ" (с моей точки зрения), то это - "повод о них поговорить".

Вот тут мы добираемся до ВТОРОГО момента - "зачем я это делаю". Просто "объяснить человеку" - это ПОЛ-ДЕЛА. А ВТОРАЯ ПОЛОВИНА состоит в том, чтобы ПОНЯТЬ - "а действительно ли человек ПРАВИЛЬНО ТЕБЯ понял".

Вот тут - когда "объясняет он тебе", а не "ты ему" - всё становится на свои места. По ходу "его объяснений" - ты начинаешь понимать - как он ТЕБЯ ПОНЯЛ.

И (по моей практике) эта МЕТОДИКА - РАБОТАЕТ.

Да и люди обычно "включаются в объяснения". Развивают, так сказать "пытливый ум". Ведь человеку ДУМАЮЩЕМУ - гораздо ИНТЕРЕСНЕЕ не чтобы "ему объясняли", а чтобы "он объяснил - как он понял". Да ещё и "аргументировал свою позицию".

Вот как-то так.

Ещё хочу рассказать об одном моменте.

Я регулярно ПРОШУ других коллег писать документацию к "моему коду".

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

Ещё раз! Я НЕ САМ пишу документацию к СВОЕМУ коду, а ПРОШУ ДРУГИХ.

Почему я делаю ИМЕННО ТАК?

Не потому, что мне ЛЕНЬ писать документацию. Отнюдь.

Смотрите какая штука.

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

Что из этого следует?

А следует ТО, что этот код мне МАКСИМАЛЬНО понятен.

Я ПОНИМАЮ - "как он работает" и "зачем вообще он написан".

ПОСЕМУ - "для меня лично" (как и для ЛЮБОГО другого автора, который работает "в здравом уме") - код МАКСИМАЛЬНО ПОНЯТЕН.

(КОНЕЧНО если в коде используются "нетривиальные алгоритмы" или обрабатываются "нечёткости ТЗ" или "граничные условия", то я обычно пишу комментарии и документацию)

(А ещё я ОБЫЧНО пишу ТЕСТЫ к коду. Особенно к тому, что "вызывает вопросы". Мало того, что тесты ВАЛИДИРУЮТ код - они ещё и служат "примером использования".

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

Но! В "обычном ходе вещей" - код мне лично (как и ЛЮБОМУ другому автору) - МАКСИМАЛЬНО ПОНЯТЕН.

Соответственно тут встаёт вопрос - "а какую документацию тут ЕЩЁ надо писать"?

Учитывая ещё тот факт, что ОБЫЧНО у нас код сопровождается UML-моделями.

ОТВЕТ - "никакую". Код и так МАКСИМАЛЬНО ПОНЯТЕН. Потому что он "написан в здравом уме" и решает те задачи, которые призван решать. (ОБЫЧНО ещё ставятся ссылки на ТЗ - "а зачем вообще этот код написан).

Всё так.

До поры, до времени.

И тут "вдруг" к тебе приходит человек, который говорит - "я не понимаю как этот код работает".

Что делать?

Вот тут ОБЫЧНО начинается процесс коммуникаций и "передачи знаний".

Начинаем обсуждать - ЧТО ИМЕННО непонятно.

Далее по пунктам:

1. Непонятно что делают методы? Может быть их имена неудачные? МОЖЕТ! Давайте переименуем? ДАВАЙТЕ! Переименовываем. Вопрос снят? Обычно - снят.
2. Непонятно - почему был выбран "алгоритм 1", а не "алгоритм 2"? Хорошо. Обсуждаем. сравниваем их. При "прочих равных". Если убеждаемся, что "алгоритм 1" лучше, чем "алгоритм 2", то всё ОСТАВЛЯЕМ как есть. Если убеждаемся, что "алгоритм 2" ЛУЧШЕ, чем "алгоритм 1", то заменяем его. И НЕ ЗАБЫВАЕМ сказать коллеге СПАСИБО.
3. Непонятные "граничные условия". Давайте напишем Assert? Обычно - "а давайте". Написали Assert - "все счастливы".
4. Непонятные структуры данных? Почему "хеш", а не "мапа"? Давайте разбираться. Опять же - тут поступаем как в случае с "алгоритмом 1" и "алгоритмом 2".

Вроде ВСЁ. Типа "разобрались".

Если я какие-то случаи забыл - пишите мне - мы их ОТДЕЛЬНО разберём.

И теперь мы подходим к вопросу о "написании документации".

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

Дальше что мы делаем?

Вот ТУТ я ПРОШУ коллегу написать ДОКУМЕНТАЦИЮ по этим вопросам.

И он её ОБЫЧНО пишет.

А потом - Я её - ВЫЧИТЫВАЮ.

Зачем? Что происходит?

А происходит тот факт, что я "передал знания", другой коллега их "принял". Он эти знания "излагает в виде ДОКУМЕНТАЦИИ", а потом "её валидирую" на предмет того - "как он понял".

Понял ли он "то что я ему хотел передать" или "недопонял".

Если - "недопонял", то итерация - ПОВТОРЯЕТСЯ.

И так до тех пор пока "все вопросы не решены".

Есть ещё один момент, что "в процессе коммуникаций и написания документации" - коллега РОДИЛ "что-то новое". ПРИНЦИПИАЛЬНО отличающееся от "исходных посылок".

Что ВАЖНО само по себе.

Тогда мы это ОБСУЖДАЕМ и смотрим "как оно может вписаться в существующие концепции". И если "вписывается", то "вписываем". И не забываем "сказать СПАСИБО коллеге".

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

Вот как-то так.

Вопросы?

Буду рад ответить.

P.S. Надо понимать ещё тот факт, что я "вроде говорю о себе", но при этом я регулярно выступаю "и другой стороной", когда "разбираюсь в чужом коде". Тогда я ОБЫЧНО пишу документацию к нему, ну или хотя бы тесты.

P.P.S.
К чему "всё это"?

К тому, что "знания НАДО не только ПЕРЕДАТЬ", но и "ПРОВАЛИДИРОВАТЬ их передачу".

И описанные техники - ОБЫЧНО работают!

P.P.P.S.
И это не потому, что я - "сноб" и "требую чего-то от других", а потому, что "дуругих путей - НЕ ВИЖУ".

Повторю - "если кто-то требует ТОГО ЖЕ от меня" - я с РАДОСТЬЮ соглашаюсь.

Тут нет "игры в одни ворота".

P.P.P.P.S. К чему я привёл картинку вначале? А к ТОМУ, что НИ ОДНО моё слово не надо читать КАК ДОГМУ. Я пытался "лишь показать best-practice". И не факт, что ЭТО НАДО ДЕЛАТЬ. Это лишь - "повод задуматься". Если бы МНЕ кто-то лет 10-15 назад показал бы подобную статью - я бы "сказал ему СПАСИБО".

О моих скриптах. Ещё один "финт ушами"

У меня есть "эмуляция вызова классовых методов".

Выглядит примерно так:

CLASS SomeClass
 VAR X
 X := 10
 PROCEDURE INC_X
  X := X + 1
 ; // INC_X
; // SomeClass

SomeClass VAR Instance1
Instance1 .INC_X
Instance1 .X WriteLn
// - будет напечатано 11

SomeClass VAR Instance2
Instance2 .X := 20
Instance2 .INC_X
Instance2 .X WriteLn
// - будет напечатано 21

Задали тут ОБЪЁМНЫЙ вопрос

"Александр, а вы когда-нибудь делали тесты, которые бы проверяли элементы предметной области на соответствие их модели?
или даже скорее наборот - соответствует ли выбранная модель предметной области
(добрый день)
У меня сейчас такая задача, которую можно реализовать двумя способами. Способы похожи в общем, но разнятся в деталях. Оба способа удовлетворят наши потребности.
каждый способ реализуется на модели данных, т.е. у меня на выбор две модели. Текущие знания предметной области вписываются в обе модели. Но: вполне возможно эти знания не полны, возможно заказчики захотят что-то поменять.
Т.е. у меня есть проблема выбора. Но суть моего вопроса к Вам даже не в этом.
Предположим я выбрал модель. Вписал в неё сущности предметной области. Всё работает. Потом в предметной области что-то меняется. Вот тут мысль о том, чтобы предметную область как-то описать отдельно от модели, и между моделью и предметной областью проложить тесты
хотя вопрос сам по себе странный - описание предметной области - это и есть модель, но всё же..
...Может я не правильно ставлю вопрос...
по сути мне нужен некий кейс, показывающий, как предметная область ложится в выбранную модель. Это наверное больше подходит на те самые тесты, которые как примеры..
(в общем я всё острее и острее ощущаю необходимость в "рисовалке")
причём даже не той, по которой генерится код, а той, которая между предметной областью и моделью"

-- ТЕМА БОЛЬШАЯ и СЛОЖНАЯ.

Могу лишь пока ОДНО сказать, что это где-то из "области управления требованиями" и их валидации.

Но пока - "возьму тайм-аут" на "подумать".

Ссылка. "Про UML"

http://www.youtube.com/watch?v=kKuiHXr6nLA&list=PLDrmKwRSNx7I1gEIH5IEW5_Kn63OIvCvK

Я сам - посмотрел, но комментировать пока не буду.

Одно только могу сказать - автор сказал ОДНУ ГЛУПОСТЬ - "отсутствие МОДЕЛЕЙ ведёт к СЛОЖНОСТИ и НЕПОНЯТНОСТИ систем".

ОТКУДА он это взял?

Где МОТИВАЦИЯ?

Что за "большевистские лозунги"?

Где "практические примеры", поясняющие, что "НАЛИЧИЕ модели упрощает разрабатываемые системы"?

Дальше он говорит про ДЕТАЛИ разработки с применение UML. Про "детали" - я тоже могу рассказать.

Но!

ГДЕ МОТИВАЦИЯ?

А ИМЕННО за МОТИВАЦИЮ нас "побили ногами" вот тут - http://habrahabr.ru/post/188604/

О "моих скриптах"

Переделал тут объявление слов и обработку параметров.

Почти отказался от конструкции WordWorker.

Теперь можно написать так:

PROCEDURE P 
 INTEGER IN aParam1
 // - Объявляем первый параметр слева
 INTEGER IN aParam2
 // - Объявляем второй параметр слева
 aParam1 + aParam2 WriteLn
;

1 3 P
// - будет напечатано число 4

Или так:

PROCEDURE P 
 INTEGER IN aParam1
 // - Объявляем параметр слева
 ^ INTEGER IN aParam2
 // - Объявляем параметр справа
 aParam1 + ( aParam2 DO ) WriteLn
;

1 P 3
// - будет напечатано число 4

Или так:

PROCEDURE P 
 ^ INTEGER IN aParam1
 // - Объявляем первый параметр справа
 ^ INTEGER IN aParam2
 // - Объявляем второй параметр справа
 ( aParam1 DO ) + ( aParam2 DO ) WriteLn
;

P 1 3
// - будет напечатано число 4

Или всё то же с функцией:

Теперь можно написать так:

INTEGER FUNCTION F 
 INTEGER IN aParam1
 // - Объявляем первый параметр слева
 INTEGER IN aParam2
 // - Объявляем второй параметр слева
 Result := ( aParam1 + aParam2 )
;

1 3 F WriteLn
// - будет напечатано число 4

Или так:

INTEGER FUNCTION F
 INTEGER IN aParam1
 // - Объявляем параметр слева
 ^ INTEGER IN aParam2
 // - Объявляем параметр справа
 Result := ( aParam1 + ( aParam2 DO ) )
;

1 F 3 WriteLn
// - будет напечатано число 4

Или так:

INTEGER FUNCTION F 
 ^ INTEGER IN aParam1
 // - Объявляем первый параметр справа
 ^ INTEGER IN aParam2
 // - Объявляем второй параметр справа
 Result := ( ( aParam1 DO ) + ( aParam2 DO ) )
;

F 1 3 WriteLn
// - будет напечатано число 4

Ну и понятно, что всё - рекурсивно:

INTEGER FUNCTION F 
 INTEGER IN aLeftParam1
 // - Объявляем первый параметр справа
 INTEGER IN aLeftParam2
 // - Объявляем второй параметр справа
 ^ INTEGER IN aRightParam1
 // - Объявляем первый параметр справа
 ^ INTEGER IN aRightParam2
 // - Объявляем второй параметр справа
 Result := ( aLeftParam1 + aLeftParam2 + ( aRightParam1 DO ) + ( aRightParam2 DO ) )
;

1 2 F 3 4 WriteLn
// - два параметра слева и два параметра справа
// - будет напечатано число 7

Ну и IN-OUT параметры:

PROCEDURE INC
 INTEGER IN-OUT theIncremented
 theIncremented := theIncremented + 1
;

VAR X
X := 10
INC X
X WriteLn
// - будет напечатано 11

На самом деле это эквивалентно следующему коду:

PROCEDURE INC
 ^ INTEGER theIncremented
 theIncremented ^:= ( theIncremented DO ) + 1
;

VAR X
X := 10
INC X
X WriteLn
// - будет напечатано 11

среда, 29 января 2014 г.

Прислали ссылку. Unit Testing in Delphi

http://forms.embarcadero.com/DelphiUnitTesting2-12

Скажу честно - я пока сам мало, что понял.

Под одним только "подпишусь":
"Without unit tests your code is fragile, hard to change, and unreliable. Unit testing is the only way that you can be sure that your code does what it is supposed to do.Without unit tests your code is fragile, hard to change, and unreliable. Unit testing is the only way that you can be sure that your code does what it is supposed to do."

Коротко. Ещё раз позанудничаю. Зачем я пишу блог?

Банально...

У меня есть наработки, которые "МНЕ ЛИЧНО КАЖУТСЯ ЦЕННЫМИ".

Я (грешным делом) думал - "напишу в блоге и ВСЕ ВСЁ поймут" :-)

НАИВНЫЙ! :-)

Зато я приобрёл БЕСЦЕННЫЙ опыт! И стал "СИЛЬНО ДУМАТЬ о мотивации" того, что я ДЕЛАЮ.

НЕ "просто сделал" и "это типа круто", а "ЗАЧЕМ я это сделал".

Какие задачи решаются?

Можно ли было обойтись другими средствами?

Я вот (тоже грешным делом) "иногда" думал, что "меня недооценивают" (в плане понимания).

И "сваливал с больной головы на здоровую"...

Теперь - Я ПОНИМАЮ - "правильную мысль ещё НАДО уметь ПРАВИЛЬНО донести" :-)

Пока НИ ОДНОЙ мысли до "широкой аудитории" - я НЕ ДОНЁС.. :-) Это - ПРАВДА...

Ну это - "повод работать над собой"...

понедельник, 27 января 2014 г.

Решил РАЗДЕЛИТЬ понятия ARRAY и ITERATABLE

По мотивам - http://programmingmindstream.blogspot.ru/2014/01/todo_24.html, и вопросам к данному посту.

Я думал - и понял - вопросы были правильные (особенно в "личке").

Решил разделить понятия ARRAY и ITERATABLE.

Зачем?

Чтобы массивы могли "остаться Mutable", а ITERATABLE - Immutable.

Чтобы - очередной раз "съэкономить на спичках".

Ну и чтобы "не путать "тёплое с мягким"".

При этом - ARRAY совместим с ITERATABLE, а ITERATABLE с ARRAY - НЕТ!

Пример:

ARRAY VAR A = [ 1 2 3 4 5 ]
// - совместимо
ARRAY VAR A = ( 1 2 3 4 5 )
// - НЕ СОВМЕСТИМО

ITERATABLE VAR A = [ 1 2 3 4 5 ]
// - совместимо
ITERATABLE VAR A = ( 1 2 3 4 5 )
// - совместимо

ITERATABLE VAR A = revert [ 1 2 3 4 5 ]
// - совместимо
ARRAY VAR A = revert [ 1 2 3 4 5 ]
// - НЕ СОВМЕСТИМО
ARRAY VAR A = [ FOR revert [ 1 2 3 4 5 ] ( IN anItem anItem ) ]
// - совместимо (потому, что массив копируется, через "обратный итератор")
ARRAY VAR A = [ ( 1 2 3 4 5 ) ]
// - совместимо (потому, что массив копируется)
ARRAY VAR A = [ FOR ( 1 2 3 4 5 ) ( IN anItem anItem ) ]
// - совместимо (потому, что массив копируется)

ARRAY VAR A = MAP INTEGER ( INTEGER IN anItem Result := anItem + 1 ) [ 1 2 3 4 5 ]
// - НЕ СОВМЕСТИМО
ITERATABLE VAR A = MAP INTEGER ( INTEGER IN anItem Result := anItem + 1 ) [ 1 2 3 4 5 ]
// - совместимо
ARRAY VAR A = [ FOR MAP INTEGER ( INTEGER IN anItem Result := anItem + 1 ) [ 1 2 3 4 5 ] ( IN anItem anItem ) ]
// - совместимо (потому, что массив копируется)

Ещё раз об "уровнях тестирования"

Я немного писал тут - http://18delphi.blogspot.ru/2013/11/gui_9423.html

Разовью тему.

Многие говорят "ах надо тестировать". (Ещё больше людей говорит конечно - "тестировать незачем" :-) Но этот пост не для них)

Зададимся вопросом - "а что именно тестировать"?

Попробую выделить "слои тестирования" и "подходящие инструменты".

Варианты следующие:

1. Тестируем "базовые классы" и "структуры данных". Тут для использования подходит "голый DUnit" (http://dunit.sourceforge.net/) и  "атомарные тесты" - http://18delphi.blogspot.ru/2013/04/blog-post_2326.html и http://programmingmindstream.blogspot.ru/2013/11/tdd_28.html. Не забываем про "пред- и пост-условия".

2. Тестировать надо классы с "параметризованным входом" (входные mock'и). Тут подходит вот какая надстройка над DUnit - http://18delphi.blogspot.ru/2013/04/blog-post_7108.html, а также - "использование эталонов" - http://18delphi.blogspot.ru/2013/04/blog-post_8791.html

3. Тестировать надо "пользовательские истории" ("базовых классов"). Тут подходит вот что - http://roman.yankovsky.me/?p=1355. Может быть также можно тестировать и "прецеденты приложения", но Роман эту тему пока не развил.

4. Тестировать надо "отдельностоящие компоненты". Тут подходит вот что - http://programmingmindstream.blogspot.ru/2014/01/openctf-component-test-framework.html

5. Тестировать надо "прецеденты приложения". Тут подходит вот что - http://18delphi.blogspot.ru/2013/11/gui.html и http://18delphi.blogspot.ru/2013/11/gui-back-to-basics_22.html и http://18delphi.blogspot.ru/2013/11/gui-dunit.html

6. Тестировать надо GUI-приложение как "чёрный" ("серый") ящик ("Честное" нажимание на "кнопки"). Тут подходит - TestComplete (http://smartbear.com/products/qa-tools/automated-testing-tools/). Ну и не забываем про - http://programmingmindstream.blogspot.ru/2014/01/blog-post_626.html (там про "серый ящик" в частности написано).

7. Тестировать надо GUI-приложение как "реальный пользователь" ("автоматам" мы не доверяем). Что тут? Тут - РУЧНОЕ ТЕСТИРОВАНИЕ. "Никаких инструментов"... Единственный инструмент это что-то вроде RequisitePro (http://www-03.ibm.com/software/products/ru/reqpro/) и написание HLTC (www.qualitytesting.info/forum/topics/low-and-high-level-test-cases?commentId=2064344%3AComment%3A427950&xg_source=activity http://pic.dhe.ibm.com/infocenter/rqmhelp/v2r0/index.jsp?topic=/com.ibm.rational.test.qm.doc/topics/c_testcases.html http://www.sqaforums.com/showflat.php?Number=663587) для "живых тестеров".

Вот как-то так...

Развить тему?

P.S. Что ещё хочу сказать?

ПРЕДПОЧТИТЕЛЬНОСТЬ тестов возрастает при движении от 7-го пункта к 1-му.

Почему?

Потому что СЛОЖНОСТЬ тестов возрастает в ОБРАТНОМ порядке - при движении от 1-го пункта к 7-му.

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

Есть ОДНО (очень важное) ИСКЛЮЧЕНИЕ - если "подобный тест" УЖЕ НАПИСАН. Тогда - уровень теста - НЕ ВАЖЕН. Надо взять УЖЕ СУЩЕСТВУЮЩИЙ тест и попытаться АДАПТИРОВАТЬ его к "новому тестируемому случаю".

воскресенье, 26 января 2014 г.

Ссылка. Coding style matters

http://www.delphifeeds.com/go/f/112257?utm_source=dlvr.it&utm_medium=facebook

Что хочу добавить?

По мне - важен не "вид стиля кодирования", а ЕГО НАЛИЧИЕ. И ОБЩНОСТЬ.

Ну а автору "хочется дать по рукам" - за 9 входных параметров.

суббота, 25 января 2014 г.

Ссылка. Управленческие инструменты: Как играть в нелинейные шахматы

http://habrahabr.ru/company/stratoplan/blog/201242/

После прочтения этого:

"Если вы обнаружили себя в правых квадратах (A и B), скорее всего у вас сейчас все в порядке с точки зрения внутренней мотивации. Интерес — один из главных внутренних мотиваторов.

И даже люди, утверждающие, что для них главный мотиватор — это деньги, как мне кажется, немного лукавят. Ведь у них наверняка есть хобби:
  • За которое им не платят
  • На которое они тратят личное время
  • За которое они сами иногда платят


Что заставляет людей заниматься хобби? Интерес, прежде всего."

-- понял УЖАСНУЮ для себя вещь - на данный момент у меня лично ХОББИ, отличного от РАБОТЫ - НЕТ.

И ЕЩЁ:
"Если менеджер приходит на работу каждый день с желанием наконец сдохнуть, нельзя ожидать, что люди в команде будут работать с горящими глазами. Люди каким-то мистическим образом считывают состояние лидера команды.

Если менеджер говорит уставшим голосом: “Боже, когда же мы наконец выкатим эту хрень...” — чего он ждет? Что вся команда поднимется с криками: “Эгегей, хрень! Покатили! Давайте две хрени выкатим!”?

Чудес не бывает. Рано или поздно состояние лидера команды начнет транслироваться на всех остальных."

И ещё:
"После хороших конференций и тренингов люди возвращаются с припадком энтузиазма. Почему? Потому что они узнали для себя что-то новое, в чем они еще не так компетентны. И у них появляются горящие глаза все это воплотить. Эффекта хватает на месяц-два. После чего надо ехать на следующую конференцию. :) Или таки разбираться с собственными целями."

И ЕЩЁ:
"Пример из жизни. Один наш коллега менеджер рассказывал после тренинга:

— Вы же сказали, что надо встречаться с людьми один на один. Я вернулся, подзываю к себе девочку-тестировщицу. Говорю, Маша, пойдем поговорим. Смотрю, она побледнела: “Сережа, что-то случилось?” Ну, говорю, я хотел бы обсудить карьерные перспективы… Гляжу, она сейчас в обморок упадет: “Сережа, у нас будут увольнения?..”

— В итоге разговорились. Выяснили, что она хочет двигаться в сторону системного анализа. Придумали какой-то план, шаги. Она собирается уходить, поворачивается и говорит: “Сереж, спасибо тебе большое.” Я вообще не понял: “За что?” — “Понимаешь, я до этого работала в двух компаниях всего 5 лет. Со мной вообще никто ни разу не говорил, что мне интересно.” Сань, я чуть не заплакал. Она поворачивается выходить. Я смотрю ей в спину и понимаю, что конкретно этому человеку в ближайшие полгода вообще никакие деньги не нужны."

Ссылка. Управленческие инструменты: Почему заказчики требуют дурацкие отчеты?

habrahabr.ru/company/stratoplan/blog/202028/

Цитата:
"На одной из конференций произошел комичный случай. Подходит слушательница:

— Александр, есть такой вопрос: Как нам повысить уровень доверия в отношениях с заказчиком?

— А что сейчас не так с уровнем доверия?

— Ну, у нас есть команда, есть менеджер. И мы хотим, чтобы заказчик доверял команде и общался только с менеджером. А он лезет напрямую к инженерам…

— А чем это плохо? Человек сразу получает ответы на свои вопросы, быстрые коммуникации и все такое.

— Понимаете… Мы ему джуниор инженеров продаем как синьор инженеров… И нам не хотелось бы, чтобы он обнаружил этот факт.


Напомню изначальную постановку вопроса: “Как нам повысить уровень доверия в отношениях с заказчиком?”"

ВЕРЮ! :-)

И ещё:
"История из жизни. Мой коллега и второй любитель управленческих инструментов Слава Панкратов рассказывал, как в свое время они работали на американского заказчика корейского происхождения Джина:

В какой-то момент команда выросла до 25 человек, а составление недельного отчета для созвона с Джином начало отнимать целый день.

Я как-то прибегаю на созвон, запыхавшийся такой. Джин говорит:

— Привет, чего бегаем?

— Ну как, вот сегодня целый день собирал данные.

Джин моментально становится серьезным:

— То есть, правильно ли я понимаю, что на этот отчет мой тест менеджер тратит четыре дня в месяц?

— Ну да

В этот момент он, видимо, умножает мою ставку на 8 часов и понимает, что недельный отчет стоит ему как-то очень много:

— Слав, давай попробуем жить без этой бумажки..."

Если бы КАЖДЫЙ "считал и умножал"...

(+)
http://18delphi.blogspot.ru/2013/05/offtopic-rup.htmlhttp://18delphi.blogspot.ru/2013/05/offtopic-rup.html
http://18delphi.blogspot.ru/2013/04/blog-post_2.html
http://18delphi.blogspot.ru/2013/04/blog-post.html

Ссылка. Управленческие инструменты: 16 концептов на каждый день

http://habrahabr.ru/company/stratoplan/blog/202856/

Отличная цитата:
"По факту писать статьи получается долго. То, что вживую ты рассказываешь за 5 минут, на бумагу излагается 2 часа. И потом люди мучительно это читают, пытаясь угадать интонацию, с которой ты все это хотел сказать.
"

Ссылка. Управленческие инструменты: Как объяснить, когда чувствуешь одним местом?

http://habrahabr.ru/company/stratoplan/blog/198870/

Цитата:
"D. Неосознанная компететность. Если опытного водителя посреди дороги похлопать по плечу и уточнить: “Скажите, пожалуйста, вы сейчас почему едете на 3-й передаче и во 2-й полосе”, он иногда испугается: “Кто здесь?” и не всегда сможет объяснить.

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

Откуда берутся рабочие конфликты? Некоторые рабочие конфликты можно объяснить как раз этой матрицей.

На одном из наших докладов как-то встал опытный дядька (лет 45) и поделился своей ситуацией:

Я — главный архитектор в компании. Ко мне студент приносит свою архитектуру. Я на нее смотрю и вижу, что она плохая. Но я уже забыл почему. Как мне объяснить студенту, что он не прав?

Если нет фактов, а убедить человека хочется, то в ход идут “авторитет”, “лучшие практики” и прочие корпоративные корабли, которые что-то бороздят:

У меня СЕМЬ ЛЕТ ОПЫТА создания архитектур, я тебе говорю. что ОНА КРИВАЯ! Что непонятно?

Что в этот момент думает молодой студент? Примерно следующее:

Мдааа, очевидно, возраст… Наш уже совсем оторвался от действительности..."

Цитата из комментов:
"Хм.
Хорошо, вот прихожу к вам я — и задаю Вам вопрос «почему „не“ с глаголом нужно писать отдельно?». 
Вы — опытный в написании «не» с глаголами дядька. Вы говорите про какое-то неведомое мне правило.
Я понимаю, что есть некое правило (стереотип) — и задаю следующий вопрос — а откуда это правило взялось.
Вы, как опытный дядька, ссылаетесь на авторитет — например, Розенталя.
Но для меня-то Розенталь — не авторитет (я — воинствующая серость, и его не знаю), я все еще не понимаю, почему писать «не» с глаголами надо раздельно в данном конкретном случае. Что Вы скажете мне? Прочитаете небольшую лекцию по филологии? Про развитие русского языка на протяжении тысячелетий?"

Ссылка. Управленческие инструменты: 4 принципа конструктивного общения или почему мы живем в режиме подвига?

http://habrahabr.ru/company/stratoplan/blog/210170/

Например:
"
Ошибка №1. Атака в прошлое.
Прибегает, например, менеджер к своему сотруднику с сакраментальным вопросом: “ПОЧЕМУ ты вчера не прогнал тесты?!!” Что в этот момент сделать сотруднику? Сесть в машину времени, метнуться в прошлое, там прогнать тесты и вернуться с уже прогнанными тестами?

С прошлым есть ровно одна проблема — его нельзя изменить. Поэтому вопросы в прошлое люди зачастую воспринимают как атаку на них лично. Более того, на вопрос “Почему ты не сделал вчера вот это” человек начинает добросовестно отвечать, почему он вчера этого не сделал. Причин у умных людей всегда много: соседний отдел поздно прислал требования, потом другой отдел долго не мог сделать сборку, тут еще директор отвлек на важную задачу и т.д.

На самом деле, то, что тесты не были прогнаны, само по себе не хорошо и не плохо. Это некий факт. Я, вот например, тоже вчера тесты не прогнал. Более того, я их уже лет пять тесты не гоняю. И пока все довольны.

Но судя по накалу эмоций, этот факт создает какую-то проблему В НАСТОЯЩЕМ. Например, менеджер не может отправить сборку заказчику. Или не может рапортовать об успешном завершении работ наверх и т.д. И вот эту проблему и надо решать в настоящем.

А когда она решена — тут как раз можно заглянуть В БУДУЩЕЕ: как бы нам сделать так, чтобы таких ситуаций больше не повторялось. И вот здесь будет уместен анализ прошлого: почему тогда тесты-то не прогнали? Но в этой точке человек уже не воспринимает это атаку на него личного. Когда текущая проблема разрешилась, виноватых уже не ищут. Мы вообще теперь будущее обсуждаем."

 Или:
"
2. Адресность.
Когда два сотрудника друг другу в курилке жалуются на начальство: “Блин, опять переезд в новый офис. Сколько можно? Третий раз за год!.. Заколебали уже...” — это не вполне конструктивно. Потому что, если есть проблема с переездами. то вряд ли они ее между собой у курилке решат.

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

Принцип адресности говорит о том, что проблему нужно решать с тем, с кем можно ее решить.

К нарушению принципа адресности очень часто относится и публичная критика кого бы то ни было. Любая публичная критика большинством людей воспринимается как атака на них лично. Что нужно сделать? Правильно — размазать источник критики. Тогда все зрители с попкорном немедленно увидят, кто прав, а кто нет. И дальше герои обсуждения расчехляют трофейные какашкометы и начинается др-р-рака!

Стоит только начать переписку лично с человеком, а еще лучше позвонить ему или прийти вживую поговорить, как градус эмоций спадает в ноль, и проблема решается сама собой.

К личной критике люди прислушиваются гораздо, гораздо лучше. И личная критика позволяет сохранять хорошие конструктивные отношения в долгосрочной перспективе."

(+) http://18delphi.blogspot.ru/2013/04/blog-post_1959.html

пятница, 24 января 2014 г.

ToDo. Написать про массивы, списки и итераторы

Есть два базовых понятия - "массив" и "итератор".

"Массив" - это структура данных.
"Итератор" - это императивная конструкция для перебора элементов массива.

Простейший пример:

ARRAY VAR A := [ 1 2 3 4 5 ]
// - Объявление массива и его инициализация
FOR A WriteLn
// - простейший итератор по массиву.
//   Принимает ДВА параметра - собственно массив и подитеративную функцию.
// - в данном примере на устройство вывода будут выведены числа 1 2 3 4 5

revert - принимает в качестве параметра массив и возвращает его "перевёрнутое отображение".

Именно - ОТОБРАЖЕНИЕ, а не КОПИЮ.

Пример:

ToDo. Написать про "Базовые конструкции" скриптовой машины, из которых выводятся все остальные "грамматики"

ToDo. Написать про "Базовые конструкции" скриптовой машины, из которых выводятся все остальные "грамматики".

Слова для описания "императива":

WordWorker - слово принимающее параметры как "слева", так и "справа"
: - слово принимающее параметры ТОЛЬКО "слева"
if - условный оператор
while - цикл с условием
Iterator - итератор по контейнеру
CompileWord - слово для компиляции других слов
[ - слово переводящее скриптовую машину в режим исполненния

Слова для описания "декларатива":

Стереотип (StereotypeStereotypeProducer)
Коллекция (NamedWordProducer)
Link (CallerAndWordWorker, WORDWORKER) %UID и U$ 

О "моих скриптах"

По мотивам - http://programmingmindstream.blogspot.ru/2014/01/embarcadero-procedure-reference-to.html?showComment=1390425848776#c4250509825918387115

У меня вот так примерно можно сделать:

FUNCTOR FUNCTION A INTEGER IN anX
 Result := ( 1 + anX )
 // возвращаем "лямбду"
; // A

PROCEDURE B
 INTEGER VAR l_Y := 10
 // - Объявляем целочисленную переменную и присваиваем ей 10
 FUNCTOR VAR l_Functor := A ( l_Y );
 // - вызываем функцию A и передаём ей переменную l_Y 
 //   и получаем "лямбду" в l_Functor
 INTEGER VAR l_Z := l_Functor DO
 // - вызываем "лямбду", сохранённую в l_Functor и получаем значение в l_Z. 
 //   l_Z теперь РАВНО 11
; // B

А вот если сделать так:

PROCEDURE B
 INTEGER VAR l_Y := 10
 // - Объявляем целочисленную переменную и присваиваем ей 10
 FUNCTOR VAR l_Functor := A ( l_Y );
 // - вызываем функцию A и передаём ей переменную l_Y 
 //   и получаем "лямбду" в l_Functor
 l_Y := 20
 INTEGER VAR l_Z := l_Functor DO
 // - вызываем "лямбду", сохранённую в l_Functor и получаем значение в l_Z. 
 //   l_Z теперь РАВНО 11, а не 21. Что - НЕОЧЕВИДНО
; // B

А вот если сделать так:

FUNCTOR FUNCTION A POINTER INTEGER IN anX
 Result := ( 1 + anX )
 // возвращаем "лямбду"
; // A

PROCEDURE B
 INTEGER VAR l_Y := 10
 // - Объявляем целочисленную переменную и присваиваем ей 10
 FUNCTOR VAR l_Functor := A ( l_Y );
 // - вызываем функцию A и передаём ей переменную l_Y 
 //   и получаем "лямбду" в l_Functor
 l_Y := 20
 INTEGER VAR l_Z := l_Functor DO
 // - вызываем "лямбду", сохранённую в l_Functor и получаем значение в l_Z. 
 //   l_Z теперь РАВНО 21, а не 11. Что - ТОЖЕ НЕОЧЕВИДНО
; // B

Но "НЕОЧЕВИДНОСТИ" - вполне объяснимы.

P.S. А если сделать так:

FUNCTOR FUNCTION A POINTER INTEGER IN anX
 Result := ( 1 + anX )
 // возвращаем "лямбду"
; // A

FUNCTOR FUNCTION B
 INTEGER VAR l_Y := 10
 // - Объявляем целочисленную переменную и присваиваем ей 10
 Result := A ( l_Y );
 // - вызываем функцию A и передаём ей переменную l_Y 
 //   и получаем "лямбду" в l_Functor
 l_Y := 20
; // B

PROCEDURE C
 FUNCTOR VAR l_Functor := B
 INTEGER VAR l_Z := l_Functor DO
 // l_Z - опять же равен 21. Что ОПЯТЬ ЖЕ - НЕОЧЕВИДНО
;

- потому что "переменные" (как и все остальные "слова словаря") это тоже - "объекты". С подсчётом ссылок.

И всеми остальными "вытекающими" последствиями...

среда, 22 января 2014 г.

Коротко. Заметки "по жизни"

По мотивам - http://programmingmindstream.blogspot.ru/2014/01/embarcadero-procedure-reference-to.html?showComment=1390421239019#c5171491385562860925

Что хочу сказать?

1. Я понял - ЗАЧЕМ Emb ARC ТАК СИЛЬНО продвигает. И дело даже не в "автоматическом уничтожении" ПОЛЬЗОВАТЕЛЬСКИХ объектов. Дело В ТОМ, что "за сценой".
2. Я ПОНЯЛ, что "лямбды" и reference to function - у Emb устроены "примерно так же как У МЕНЯ". В моей скриптовой машине. Через "интерфейсы" (объекты "словаря"), подсчёт ссылок и "захват контекста". Ничто не ново... (Это я про себя)
3. В "таком разрезе" - БЕЗ ARC - сложно обойтись.

За "подробностями" - к серии постов "GUI тестирование по-русски". Вот - начало - http://18delphi.blogspot.ru/2013/11/gui.html

Ну и последующие "одноимённые посты".

А "конца" - пока нет. Серию я ещё не закончил.

И ещё!

Читаем по ссылке - http://docwiki.embarcadero.com/RADStudio/XE5/en/Anonymous_Methods_in_Delphihttp://docwiki.embarcadero.com/RADStudio/XE5/en/Anonymous_Methods_in_Delphi

Вот цитата:
"A motivation for using method references is to have a type that can contain a bound variables, also known as closure values. Since closures close over their defining environment, including any local variables referenced at the point of definition, they have state that must be freed. Method references are managed types (they are reference counted), so they can keep track of this state and free it when necessary. If a method reference or closure could be freely assigned to a method pointer, such as an event, then it would be easy to create ill-typed programs with dangling pointers or memory leaks."

И ещё одна:
"It is possible to create a cycle in the method reference/frame link chains that causes a memory leak. For example, storing an anonymous method directly or indirectly in a variable that the anonymous method itself captures creates a cycle, causing a memory leak."

Что хочу сказать?

Я вот в "своей скриптовой машине" этих проблем - избежал.

Счастливо избежал.

"Практика - критерий истины".

У меня есть несколько сотен тестов собственно для скриптовой машины.

И они показывают, что "утечек нет".

Код например тут - https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/RealWork/ScriptEngine/

или тут - https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/RealWork/ScriptEngine/kwCompiledWord.pas

"техника" примерно такая:
procedure TkwCompiledWord.DoAddCodePart(aWord: TtfwWord;
  AtStartOfCode: Boolean;
  const aCtx: TtfwContext);
//#UC START# *4DB6CB1703AD_4DB6CA4F010D_var*
var
 l_Holder : TkwForwardDeclarationHolder;
//#UC END# *4DB6CB1703AD_4DB6CA4F010D_var*
begin
//#UC START# *4DB6CB1703AD_4DB6CA4F010D_impl*
 Assert(aWord <> Self);
 // - чтобы избежать циклических ссылок
 if (f_Code = nil) then
  f_Code := TtfwWordRefList.Create;
 if aWord.IsForwardDeclaration {AND
    (TkwForwardDeclaration(aWord).RealWord = Self)}
    // - проверка специально убрана, т.к. бывает вложенность
    then
 // - чтобы избежать циклических ссылок
 begin
  l_Holder := TkwForwardDeclarationHolder.Create;
  try
   l_Holder.f_Holded := aWord;
   if AtStartOfCode then
    f_Code.Insert(0, l_Holder)
   else
    f_Code.Add(l_Holder);
  finally
   FreeAndNil(l_Holder);
  end;//try..finally
 end//aWord.IsForwardDeclaration
 else
 if AtStartOfCode then
  f_Code.Insert(0, aWord)
 else
  f_Code.Add(aWord);
//#UC END# *4DB6CB1703AD_4DB6CA4F010D_impl*
end;//TkwCompiledWord.DoAddCodePart
-- ну и не надо забывать, что этот код "сильно устарел". Сейчас у меня "гораздо более продвинутые техники". Ну как всегда "на коленке"...

Ссылка. OpenCTF - component test framework

http://sourceforge.net/projects/openctf/

По мотивам:

Что сказать?

Ну "из той же серии". И ЗАСЛУЖИВАЕТ ВНИМАНИЯ.

Но "не совсем то".

P.S. Тем кто "намекает на велосипед" - скажу - они начали в 2007-м году, ну и я примерно где-то так же начал.

вторник, 21 января 2014 г.

По результатам "осенней мобилизации"

По результатам:

http://programmingmindstream.blogspot.ru/2014/01/tap-tap-on-google-play.html
http://programmingmindstream.blogspot.ru/2014/01/nexus-4.html
http://programmingmindstream.blogspot.ru/2014/01/nexus-10-embarcadero.html

-- ПРЯМ ЗАВИДУЮ!!! :-)

Хочется сказать что-то вроде - "надо было мне участвовать".. :-)

ШУЧУ!

Поздравляю ПАРНЕЙ!!! :-)

ИСКРЕННЕ ЗА НИХ РАД :-)

А что до того, что "сам" - ну "некогда в конкурсах участвовать"...

И это не "отмазка"...

Я "в угоду" неучастия в конкурсах написал пару хороший статей (их правда пока не оценили) и сделал МНОГО задач "ПО РАБОТЕ". Ну и "более того" - я ПРОДВИНУЛСЯ к кодогенерации - http://programmingmindstream.blogspot.ru/2014/01/blog-post_21.html

Это я думаю пока "малопонятно".. Но со временем - это БУДЕТ ПОНЯТНО...

Коротко. Для "совсем знающих". Переделываю "криптованный язык"...

Перемыл тут "шаблоны кодогенерации".

Из:

 <%CX>

Получил:

 for 'C' |==>
 begin
  OBJECT IN %C
  %C ExecuteGenerator
 end; // for

Многословно..

Но!

"Это ещё не вечер"...

Update: 

А в итоге получилось вот что:

 for Self.Children
 begin
  OBJECT IN aChild
  aChild .ExecuteGenerator
 end; // for

или

 for .Children
 begin
  OBJECT IN aChild
  aChild .ExecuteGenerator
 end; // for

Ну и в итоге рекурсивно:

 for .Children
 begin
  OBJECT IN aChild
  for .Children
  begin
   OBJECT IN aChild
   aChild .ExecuteGenerator
  end; // for
  aChild .ExecuteGenerator
 end; // for

-- .Children - оно "контекстно зависимое", от "первого параметра вызывающего слова", ну как от Self или this.

!!! Я бы конечно не стал бы морочиться с подобной "контекстной зависимостью", тем более, что "дураку" она понимания не добавляет.

Но к сожалению её "пронизан" ИСХОДНЫЙ "криптованный язык".

И АВТОМАТОМ перемыть шаблоны БЕЗ ЕЁ выкидывания - не получилось.

Но "руками" код УЖЕ можно писать и БЕЗ "контекстной зависимости".

Вот так:

 for Self.Children
 begin
  OBJECT IN aChild
  for aChild.Children
  begin
   OBJECT IN aChild
   aChild .ExecuteGenerator
  end; // for
  aChild .ExecuteGenerator
 end; // for
В идеале конечно хотелось бы так:
 for auto aChild in Self.Children
 begin
  for auto aChild in aChild.Children
  begin
   aChild .ExecuteGenerator
  end; // for
  aChild .ExecuteGenerator
 end; // for

-- И БУДУ к этому стремится.

Но ПОКА - не получается.

Что такое "auto" людям знакомым с C++11 - Должно быть известно :-)

Хотя "для скриптов" можно наверное и БЕЗ auto.

Вот так:

 for aChild in Self.Children
 begin
  for aChild in aChild.Children
  begin
   aChild .ExecuteGenerator
  end; // for
  aChild .ExecuteGenerator
 end; // for

Ссылка. Документация от Embarcadero о совместимости "procedure" и "reference to procedure"

http://docwiki.embarcadero.com/RADStudio/XE5/en/Anonymous_Methods_in_Delphihttp://docwiki.embarcadero.com/RADStudio/XE5/en/Anonymous_Methods_in_Delphi

Для таких как Я "не читавших".

Там ЕСТЬ О ЧЁМ подумать.

Например о том - "как ресурсы захватываются" и "какое их время жизни".

И "как это связано с ARC".

Для "пищи ума" приведу простейший пример:

program Test;

type
 X = reference to procedure;
 A = class
  protected
   f_Field : Integer;
  public
   procedure B;
 end; // A

var
 l_X : X;

procedure A.B;
begin
 l_X := procedure (Self.f_Field := Self.f_Field + 1;);
end;

var
 l_A : A;
begin
 l_A := A.Create;
 l_A.B;
 l_A.Free;
 l_X;
end;

-- каково поведение этого кода?

P.S. Ну и ещё "пища для мозгов" - https://plus.google.com/+RomanYankovsky/posts/cvJgAAZmhw6

пятница, 17 января 2014 г.

Ссылка. http://bottlenose.com/

http://bottlenose.com/

Не знаю "что такое", но "выглядит КРАСИВО".

Вот если бы мне так UML визуализировать.. Сразу бы нашёл "адептов"..

Ссылка. Announcing Castalia 2014.1, with Function Prototype Synchronization

http://www.delphifeeds.com/go/f/111926?utm_source=dlvr.it&utm_medium=facebook

Что сказать? Интересно конечно.. забавно.. круто.. Уважаю.

Но я для всего этого использую UML и кодогенерацию.

Там "поменял сигнатуру виртуальной функции" и сразу автоматом поменялись 135-ть override'ов в других модулях.

Или поменял "метод генерации String на WideString" и поменялось в 1024-х модулях.

Про примеси, синглетоны, publisher/subscriber, а также итераторы и тестовую аксиоматику, а также "автоматические" IfDef и секции uses - так вообще молчу...

А что касается разделения на "секцию интерфейса" и "секцию реализации". Так это вообще - "ДИКОСТЬ". Давно пора сделать если не язык, то редактор, который сам автоматически их синхронизирует. Ну 21-й век на дворе...

Что ещё сказать?

Вот в xCode и Objective-C мне крайне НРАВИТСЯ, что приватные методы можно не объявлять в интерфейсной секции класса. А в C++ нравится, что реализацию методов можно писать прямо в h-файлах. Правда они при этом делаются inline. Но это не беда. Особенно при современных гигагерцах и терабайтах.

А вообще говоря - "скрестить" бы все "эти подходы", не забывая про UML.

А ещё бы я ввёл квалификатор метода - notvirtual. По аналогии с virtual, final (sealed). Хочешь - ставь квалификатор. Но! Это ТВОЁ ОСОЗНАННОЕ решение, а иначе - пусть компилятор разбирается.

И ещё.. По мотивам - http://programmingmindstream.blogspot.ru/2014/01/freeandnil.html?showComment=1389911523375#c3709559021046326060

По-моему уже назрела НЕОБХОДИМОСТЬ в синергии языковых подходов.

Скажу КРАМОЛЬНУЮ мысль! По-моему надо (китам индустрии) уже договориться и сделать УЖЕ один "КОШЕРНЫЙ" язык. Учитывающий особенности многообразия.

Я конечно понимаю - "конкуренция и всё такое" :-)

Меня конечно сочтут "мечтателем" и "велосипедоизобретателем"...

Но я продолжу...

Ещё бы конечно здорово базировать этот КОШЕРНЫЙ ОБЩИЙ язык на графическом представлениии. Ну типа UML. А лучше - "чертежей". Почему?

Отвечу. Я писал вот тут - http://programmingmindstream.blogspot.ru/2014/01/uml.html

Лично для меня код представляется "разноцветными квадратами и стрелками".

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

Ответ - "я и так помню где в коде что находится" - не катит. Я САМ - УНИКАЛЬНЫЙ РАЗРАБОТЧИК (без ложной скромности) - я ПОМНЮ где и что находится в 15 млн строк кода. Не верите? Спросите моих коллег. Ну если вы такой же "УНИКУМ" и пытаетесь спорить - то наверное тут мы не найдём общий язык. Видимо у вас "свой путь", а у меня - свой.

Продолжу.

И даже если я работаю с диаграммой на которой - "более ста элементов" (как например вот тут - http://18delphi.blogspot.ru/2013/09/blog-post_1303.html. За что меня уважаемый мною NameRec долго "бил ногами") - этот подход всё равно работает.

Поверьте мне НА СЛОВО.

Моторику не обманешь.

Я НЕ ДУМАЮ - "а где этот элемент находится", я ПРОСТО "кидаю мышь в ту или иную сторону - в которую мне подсказывает моя моторика". Иногда - ПРОМАХИВАЮСЬ. Но! ОЧЕНЬ РЕДКО.

Но тут "дистанционно" я конечно "никого не убежу". Тут надо "опыт" и "понимание принципов работы". А иначе про "коня в вакууме" можно БЕСКОНЕЧНО спорить.

Надо ПОКАЗЫВАТЬ - "как оно работает". Как? Пока - НЕ ЗНАЮ. А надо ли?

Что до "программирования" и IDE "нового поколения" (http://programmingmindstream.blogspot.ru/2013/12/ide.html), то я себе мыслю это так:

Это не "разрозненный набор тулзов, тулзочек и утилит", а нечто "монолитное и целостное". Ну скажем Eclipce - отчасти является "примером для подражания". Но лишь ПРИМЕРОМ.

Китам индустрии надо сделать "что-то такое", что с одной стороны держит программиста в рамках:
1. ТЗ
2. Внешнего дизайна (скриншотов)
3. Модели. UML или "чертежей" (тут уж как получится)
4. Набора тестов (связанных в итоге с ТЗ и внешним дизайном)

А с другой стороны, подталкивающее программиста к использованию:
1. Аспектов и примесей
2. Шаблонов проектирования
3. Инструкции программирования (в конце концов)

Я для себя лично в "текущей разработке" выделяю четвёрку:
1. ТЗ
2. Модель
3. Код
4. Тесты

Но! Почему бы не пойти дальше?

Скажем так... "Атлас машин и механизмов" или "номенклатура микросхем".

Скажете - "это всё было.. компонентный подход и всё такое".

Конечно!

А ещё раньше были БИБЛИОТЕКИ.

Но! На дворе же - 21-й век.

Надо же "двигаться дальше".

Сделать что-то вроде - http://programmingmindstream.blogspot.ru/2013/12/blog-post_5331.html но не "на закорючках", а для "нормальных людей".

Это я всё к чему?

Ну "ГЛУПО" думать о "синхронизации прототипов функций" в "интерфейсной" части и части реализации. Ну ГЛУПО!

21-й век на дворе.

Век терабайтов и гигагерц.

Надо УЖЕ ДУМАТЬ о вещах более ВЫСШЕГО ПОРЯДКА.

Не о строках кода, а о "цветных квадратах" и "стрелках между ними" как минимум.

Ссылка. Delphi XE5 и MongoDB. Вот это кстати интересно

http://blogs.embarcadero.com/asovtsov/index.php/archives/615

Про MongoDB я много наслышан, правда сам руками не щупал.

Что могу сказать "от себя"?

Технику NoSQL - я ОБЕИМИ РУКАМИ поддерживаю.

От JSon у меня есть "некоторая аллергия". Ну "практически-технологического" плана.

Так как я видимо сталкивался с "особенностями кривизны реализации".

А вообще говоря JSon - не сильно отличается от EVD, который я "сам изобрёл" и который мы используем уже более 15-ти лет.

Так что "аллергия" тут чисто "вкусовая".

Ну а для "совсем интересующихся" примеры EVD:
https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/RealWork/Everest/testset/Controls/Controls1.evd

https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/RealWork/Everest/testset/complextable/1.evd

https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/RealWork/Everest/testset/complextable/2.evd

https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/RealWork/Everest/testset/verticalmerge/2.evd

Ну и ссылка на документацию - https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Doc/%D0%A0%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%BE%D1%80_EVD.doc

четверг, 16 января 2014 г.

Ссылка. Outsourcing плюс backsourcing минус проблемы

http://habrahabr.ru/post/207888/

Далеко не всё понял...

P.S. Offtopic. Я бы конечно "поаутсорсил бы" на Embarcadero... Но кому это нужно.. С моим-то характером...

P.P.S. Вот тут я кстати ПОЛНОСТЬЮ СОГЛАСЕН:

  • Когда нам считают деньги внешнего проекта, то туда не заносят стоимость времени внутренних сотрудников на помощь аутсорсерам, хотя бы на составление ТЗ.
  • Стоимость разработки определяется качеством кода. Качество кода нужно для снижения стоимости сопровождения/модификации/развития системы. Но нужно это «своим», а не «внешним».
  • Качество разработки зависит от степени протестированности. В прикладной разработке написать кейсы может только человек, знакомый с предметной областью. Тут как бы уже и требовать неприлично такое с аутсорсеров.
  • Срок выполнения типового проекта соизмерим с периодом генерации новых бизнес-идей, поэтому велика вероятность (чем дальше, тем вероятнее), что в финале вам выдадут заранее устаревшую по функционалу систему.
  • Гибкость и модифицируемость системы определяется архитектурой. Архитектура внешних решений часто бывает одноразовой. Очень велик соблазн сделать «жёсткосварную» конструкцию из прутков, чем точить на станке универсальные многоразовые узлы.

  • Я наблюдал "все эти пункты" в ЖИЗНИ.

    Коротко. "Нелюбителям" FreeAndNil

    По мотивам - http://programmingmindstream.blogspot.ru/2013/12/blog-post_3160.html

    Что хочу сказать?

    Одну ПРОСТУЮ ВЕЩЬ. Стоит ЛИШЬ посмотреть НОВЫЕ исходники от Embarcadero.

    В частности FM.

    Чтобы увидеть, что FreeAndNil - там ИСПОЛЬЗУЕТСЯ ПОВСЕМЕСТНО.

    По-моему это - не "просто так".

    По крайней мере это - "согласуется с МОИМ ЛИЧНЫМ ПРАКТИЧЕСКИМ опытом".

    Про class constructor'ы №3

    По мотивам - http://programmingmindstream.blogspot.ru/2014/01/class-constructor-2.html

    И даже если сделать так:
    unit Unit1;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
      FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
      FMX.Layouts, FMX.Memo;
    
    type
      TForm1 = class(TForm)
        Memo1: TMemo;
        procedure FormShow(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    type
     TA = class
      strict protected
       class var f_list: TList;
      protected
       class function CreateList: TList; virtual;
      public
       class constructor Create;
       class function List: TList;
     end;//TA
    
     TSomeOtherList = class(TList)
     end;//TSomeOtherList
    
     TB = class(TA)
      strict protected
       class var f_Fake: Integer;
      protected
       class function CreateList: TList; override;
      public
       class constructor Create;
     end;//TB
    
    class function TA.List: TList;
    begin
     Result := f_List;
    end;
    
    class function TA.CreateList: TList;
    begin
     Result := TList.Create;
    end;
    
    class constructor TA.Create;
    begin
     inherited;
     f_List := CreateList;
    end;
    
    class constructor TB.Create;
    begin
     inherited;
     f_Fake := 1000;
    end;
    
    class function TB.CreateList: TList;
    begin
     Result := TSomeOtherList.Create;
    end;
    
    {$R *.fmx}
    
    procedure TForm1.FormShow(Sender: TObject);
    begin
     TB.List;
     TA.List;
     TB.List;
    end;
    
    end.
    

    То мы получим "неожиданные результаты".

    TB.Create - наконец ТАКИ - ВЫЗОВЕТСЯ, а вот inherited из него - НЕТ.

    А если написать так:

    class constructor TB.Create;
    begin
     inherited Create;
     f_Fake := 1000;
    end;
    

    То мы получим ошибку компиляции.

    Наиболее интересующиеся читатели - могут сами попробовать.

    Что сказать? "НЕОЖИДАННО"! Но ВПОЛНЕ ОБЪЯСНИМО.

    Ну и конечно код примера доступен тут - https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/DraftsAndScketches/SomeTestProjects/ClassConstructor2/

    Про class constructor'ы №2

    По мотивам - hhttp://programmingmindstream.blogspot.ru/2014/01/class-constructor.html

    И даже в таком примере не вызовется ни TB.CreateList, ни (что "УДИВИТЕЛЬНО") TB.Create:

    unit Unit1;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
      FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
      FMX.Layouts, FMX.Memo;
    
    type
      TForm1 = class(TForm)
        Memo1: TMemo;
        procedure FormShow(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    type
     TA = class
      strict protected
       class var f_list: TList;
      protected
       class function CreateList: TList; virtual;
      public
       class constructor Create;
       class function List: TList;
     end;//TA
    
     TSomeOtherList = class(TList)
     end;//TSomeOtherList
    
     TB = class(TA)
      protected
       class function CreateList: TList; override;
      public
       class constructor Create;
     end;//TB
    
    class function TA.List: TList;
    begin
     Result := f_List;
    end;
    
    class function TA.CreateList: TList;
    begin
     Result := TList.Create;
    end;
    
    class constructor TA.Create;
    begin
     inherited;
     f_List := CreateList;
    end;
    
    class constructor TB.Create;
    begin
     inherited;
    end;
    
    class function TB.CreateList: TList;
    begin
     Result := TSomeOtherList.Create;
    end;
    
    {$R *.fmx}
    
    procedure TForm1.FormShow(Sender: TObject);
    begin
     TB.List;
     TA.List;
     TB.List;
    end;
    
    end.
    

    Исходный код примера тут - https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/DraftsAndScketches/SomeTestProjects/ClassConstructor1/

    Так что "ещё раз" - будьте осторожны.

    В ТРАКТОВКЕ "новых языковых" фич.

    Про class constructor'ы

    По мотивам - http://programmingmindstream.blogspot.ru/2014/01/todo-class-constructor.html

    На заданный там вопрос отвечает следующий пример - https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/DraftsAndScketches/SomeTestProjects/ClassConstructor/

    Вот код:

    unit Unit1;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
      FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls;
    
    type
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    type
     TA = class
      strict protected
       class var f_list: TList;
      protected
       class function CreateList: TList; virtual;
      public
       class constructor Create;
       class function List: TList;
     end;//TA
    
     TSomeOtherList = class(TList)
     end;//TSomeOtherList
    
     TB = class(TA)
      protected
       class function CreateList: TList; override;
     end;//TB
    
    class function TA.List: TList;
    begin
     Result := f_List;
    end;
    
    class function TA.CreateList: TList;
    begin
     Result := TList.Create;
    end;
    
    class constructor TA.Create;
    begin
     inherited;
     f_List := CreateList;
    end;
    
    class function TB.CreateList: TList;
    begin
     Result := TSomeOtherList.Create;
    end;
    
    {$R *.fmx}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
     TB.List;
     TA.List;
     TB.List;
    end;
    
    end.
    

    Что мы видим?

    Достаточно поставить Break-Point'ы в TA.CreateList и TB.CreateList.

    И мы увидим, что в TA.CreateList мы - ПОПАДАЕМ, а в TD.CreateList - никогда НЕ ПОПАДАЕМ.

    Что в общем - НЕОЖИДАННО, но - ВПОЛНЕ ОБЪЯСНИМО.

    Короче... БУДЬТЕ ОСТОРОЖНЫ с "новыми языковыми фичами".

    Они могут работать НЕ ТАК как вы их ТРАКТУЕТЕ.

    Лучше всего - "сначала попробовать".

    среда, 15 января 2014 г.

    Вопрос. Как "снять мультик"?

    По мотивам - http://programmingmindstream.blogspot.ru/2014/01/uml.html

    Тут я задумался. А не снять ли мне "мультик" типичной работы с моделью и кодом. Ну чтобы "проиллюстрировать мысль".

    Может быть кто-то из читателей знает как это делается?

    Можно как-то "записать мультик" собственной работы в приложениях Windows?

    А то - я же - чайник.

    ToDo. Class constructor и виртуальность

    По мотивам - http://programmingmindstream.blogspot.ru/2014/01/class-constructor-class-destructor.html

    Вот мне интересно, что будет, если написать что-то вроде:

    type
     TA = class
      strict protected
       class var f_list: TList;
      protected
       class function CreateList: TList; virtual;
      public
       class constructor Create;
     end;//TA
     
     TSomeOtherList = class(TList)
     end;//TSomeOtherList
     
     TB = class(TA)
      protected
       class function CreateList: TList; override;
     end;//TB
    
    class function TA.CreateList: TList;
    begin
     Result := TList.Create;
    end;
    
    class constructor TA.Create;
    begin
     inherited;
     f_List := CreateList;
    end;
    
    class function TB.CreateList: TList;
    begin
     Result := TSomeOtherList.Create;
    end;
    
    
    Мы в TB.CreateList попадём?

    И Когда? И попадём ли в TA.CreateList?

    И когда?

    ИНТЕРЕСНЫЙ вопрос... ЗАВТРА - ПРОВЕРЮ...

    Переделываем синглетон

    Буквально ВЧЕРА я узнал про class Constructor и class Destructor - http://programmingmindstream.blogspot.com/2014/01/class-constructor-class-destructor.html

    Я "вдохновился новыми знаниями" и решил переписать уже знакомый (http://18delphi.blogspot.ru/2013/11/gui-back-to-basics_22.html) синглетон (http://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D0%B3%D0%BB%D1%82%D0%BE%D0%BD_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)).

    Было:

    unit Script.Axiomatics;
    
    interface
    
    uses
     Script.Dictionary
     ;
    
    type
     TscriptAxiomatics = class(TscriptDictionary)
      private
       class var f_Instance : TscriptAxiomatics;
      public
       class function Instance: TscriptAxiomatics;
     end;//TscriptAxiomatics
    
    implementation
    
    uses
     System.SysUtils
     ;
    
    class function TscriptAxiomatics.Instance: TscriptAxiomatics;
    begin
     if (f_Instance = nil) then
      f_Instance := TscriptAxiomatics.Create;
     Result := f_Instance;
    end;
    
    initialization
    
    finalization
     FreeAndNil(TscriptAxiomatics.f_Instance);
    
    end.
    

    Стало:

    unit Script.Axiomatics;
    
    interface
    
    uses
     Script.Dictionary
     ;
    
    type
     TscriptAxiomatics = class(TscriptDictionary)
      strict private
       class var f_Instance : TscriptAxiomatics;
      public
       class function Instance: TscriptAxiomatics;
       class destructor Destroy;
     end;//TscriptAxiomatics
    
    implementation
    
    uses
     System.SysUtils
     ;
    
    class destructor TscriptAxiomatics.Destroy;
    begin
      FreeAndNil(f_Instance);
      inherited;
    end;
    
    class function TscriptAxiomatics.Instance: TscriptAxiomatics;
    begin
     if (f_Instance = nil) then
      f_Instance := TscriptAxiomatics.Create;
     Result := f_Instance;
    end;
    
    end.
    

    Результирующий код доступен тут - https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/GUITests/Chapter3/Scripting/Script.Axiomatics.pas

    вторник, 14 января 2014 г.

    Ссылка. Эволюция сборщика мусора в Ruby. RGenGC

    http://habrahabr.ru/post/208256/

    Чем это интересно?

    Да хотя бы "грядущим" ARC...

    Я бы конечно "скрестил бы" ARC и GC.

    Чтобы уменьшить "необходимость срабатывания" GC.

    P.S. не "про Delphi" я тут конечно. Точнее "не совсем про Delphi".