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

Днес научих, че във Pharo изпълнението на:

[v := 1] ensure: [self halt. v := 2]

ще завърши с настройка v = 2, дори когато изоставим процеса в прозореца halt (!).

Намирам това за спорно. За мен семантиката на #ensure: означава, че последователността

self halt. v := 2

трябва да се изпълни, независимо от обстоятелствата с приемния блок, не независимо от логиката на аргументния блок. И тъй като логиката на #halt включва събитието за прекратяване на процеса, намирам за натрапчива упоритата оценка на второто изречение.

След това опитах следното:

[v := 1] ensure: [1 / 0. v := 2]

Когато се появи изключение ZeroDivide, затворих програмата за отстраняване на грешки и все още стойността на v беше 2 (същото като при #halt.)

Накрая оцених:

[v := 1] ensure: [n := 1 / 0. v := v + n]

и затвори програмата за отстраняване на грешки при изключението ZeroDivide. Този път стойността на v беше 1, но не получих изключение от факта, че v + n не може да бъде оценено. С други думи, грешката продължи безшумно.

Та въпросът ми е. Каква е рационалната основа зад това поведение? Не трябва ли процесът просто да приключи в точката, в която би приключил при „нормални“ обстоятелства, т.е. без участие на #ensure:?


person Leandro Caniglia    schedule 06.09.2015    source източник
comment
Не виждам въпроса ви в пощенския списък на разработчиците на pharo. Би било много по-подходящо там (и в скърцащия), отколкото тук   -  person Stephan Eggermont    schedule 06.09.2015
comment
@StephanEggermont: Фактът, че е също подходящо в пощенския списък, не го прави неподходящо тук. Според мен твърде много знания се губят в тези пощенски списъци... те просто не са нещо за всеки. ;-)   -  person Amos M. Carpenter    schedule 06.09.2015
comment
Това е неподходящо, защото се нуждае от дискусии за компромис в дизайна, а не от отговори. Ние използваме пощенските списъци за това, а не SO. Дублирането на неща тук е добре, но централната точка е и остава пощенският списък (докато не изградим нещо по-добро в изображението)   -  person Stephan Eggermont    schedule 06.09.2015
comment
@StephanEggermont: Съвсем честно, но няма начин Леандро или някой друг да знае дали даден проблем, с който се сблъсква, е нещо, което се нуждае от дискусии за компромис, когато се натъква на неща, които не са лесно обясними веднага.   -  person Amos M. Carpenter    schedule 07.09.2015
comment
Хей, @Amos, това е Леандро, за когото говорим. Той знае :) Все пак имаш право.   -  person Stephan Eggermont    schedule 07.09.2015
comment
@StephanEggermont вашето възражение е технически правилно (на @AmosMCarpenter също!). Но Smalltalk трябва да присъства на открити форуми като StackOverflow, защото имаме нужда от повече видимост.   -  person Leandro Caniglia    schedule 07.09.2015
comment
@StephanEggermont: Ха, вероятно е вярно. :-Д   -  person Amos M. Carpenter    schedule 07.09.2015


Отговори (2)


Интересен един. Изглежда, че вашият отговор се крие в метода BlockClosure>>valueNoContextSwitch, който се извиква от #ensure:. Ако прочетете коментара там, той казва, че създава точно копие на BlockClosure>>value (в примитив) и се връща върнатата стойност на това копие, а не върнатата стойност на оригиналния блок, съдържащ вашия halt, който сте прекратили. Така че копието се изпълнява (очевидно игнорирайки копирания halt), дори ако оригиналът не успее да завърши.

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

person Amos M. Carpenter    schedule 06.09.2015

Предполагам, че това е поведение, което не е напълно дефинирано от нито един (ANSI) стандарт, но ме поправете, ако греша.

Други Smalltalks изглежда се държат различно. Опитах го в Smalltalk/X, където Debugger предлага 3 опции: „Продължи“ (т.е. продължаване), „Прекратяване“ (т.е. размотаване) и „Прекратяване“ (т.е. спиране на процеса). Предполагам, че "Прекратяване" отговаря на това, което Squeak прави, когато затворите дебъгера.

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

При прекратяване и прекратяване (които и двете се отвиват към съответните манипулатори на изключения), той не трябва да се опитва да преоцени или продължи потенциално грешен/лош/неуспешен блок за осигуряване.

Това е изборът на манипулатора (какъвто всъщност е Debugger) дали иска да продължи или не. Ако не, тогава той трябва да излезе от блока за осигуряване и да продължи да изпълнява всички други блокове за осигуряване, които може да са по-горе във веригата за извикване.

Това е в съответствие с поведението на блоковете за обработка на изключения, които също не се преоценяват или продължават, ако същото изключение бъде повдигнато вътре. В ST/X има изричен код в класовете за изключения, който се грижи за тази ситуация, така че определено е по предназначение, а не по страничен ефект.

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

person blabla999    schedule 29.10.2015