Здравствуйте, Astaroth, Вы писали:
A>Здравствуйте, WolfHound, Вы писали:
WH>>Но водить в язык конструкции которые практически не востребованы...
A>Примерно это мне всегда хотелось сказать тому, кто придумывал Perl...
Не флейма ради, а самообразования для: например?
(Еще раз: я не собираюсь спорить. Мне действительно интересно Ваше мнение.)
VladD2:
> ПК>Где у учеников будет больше вопросов относительно разницы в работе двух примеров?
> Ну, если первы вариант Шарп, то конечно во втором. Так как в первом будет только один вопрос: А почему компилятор написал что не может изменить строку так как она доступна тольк для чтения.
Там нет Шарпа. Там псевдокод, отличающийся только обозначением ссылок. Естественно, предполагается, что оба примера работают, и делают одно и то же, а именно модифицируют s1 через s2. Мы ж не занимаемся ерундой типа "X vs. Y", а просто обсуждаем выдвинутый тобой тезис о том, что неявные ссылки проще для обучения.
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Понимаетели, Вы привели случай, когда чужой модуль использует Ваш модуль: "импорт функций из моего модуля". А надо наоборот. Вы используете чей-то чужой УЖЕ написанный модуль и Вам надо в этот чужой уже написанный модуль как-то передать свою функцию обратного вызова (call-back function). Если в языке нет процедурных переменных (указателей на функцию), то сделать это Вы не сможете.
Совершенно очевидно, что если модуль УЖЕ написан и УЖЕ использует каки-то фичи моего модуля, то избавиться от этих фич не получится. Но это к НАШЕМУ вопросу не относится.
Здравствуйте, WWL, Вы писали:
WWL>Здесь не может быть циклических ссылок между компонентами системы. WWL>Сергей и говорит Вам о том, что указатель на функцию — это "страховка" для одного модуля гарантированно вызывать функции, которые "ещё не написаны" (виртуальность).
Никакие циклические ссылки здесь не нужны. Нужна всего лишь одна хорошо известная функция в каждом модуле. Я бы еще добавил, что подход с"хорошо известными функциями" широко используется как раз в компонентых системах — COM, например.
Вероятно, в широко разрекламированном обероне тоже
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Переменная типа Element есть УКАЗАТЕЛЬ на размещенный в куче объект. Если объект не размещен, то эта переменная есть null. Обратите внимание: не объект равен null, а переменная типа Element равна null. Еслибы Element не был бы указетелем, то струтура Element в силу своего рекуррентного определения была бы бесконечного размера.
Есть такая идиома, как ленивые вычисления. В ФЯ она развёрнута во времени, а в ссылочных типах — в пространстве.
Казалось бы, вызов любой рекурсивной функции, использующей ветвление — это бесконечность
;;;; лисп
(defun sum-of-ints (n) (if (= n 0) 0 (+ n (sum-of-ints (- n 1)))))
;;;; как это было бы:
sum-of-ints(1)
if(=(1,0),0,sum-of-ints(-(1,1)))
=(1,0)
nil
-(1,1)
0
sum-of-ints(0)
if(=(0,0),0,sum-of-ints(-(0,1)))
=(0,0)
t
-(0,1) ;;;; жадные вычисления
-1
sum-of-ints(-1)
.....
Но благодаря выборочной ленивости (в лиспе нужно соответствующим образом определять функции; в частности, таковыми являются if, cond, quote) мы не проваливаемся в выражение "до днища".
Null — это дефолтное значение объекта.
Если программа, развёртывающая тот же самый список во времени, написана не ногами, она обязательно остановится на проверке if(next==null).
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>И в некотором смысле он может оказаться правым Все зависит от определений. Похоже, у него более общее определение понятия "указатель", не привязанное к C или C++ и адресной арифметике. Скажем, в том же Паскале указатели были ближе к ссылкам в Шарпе, чем к указателям в C++. Если я, конечно, еще не окончательно Паскаль забыл
Указатели С/С++ точно такие же, как в Паскале, а адресная арифметика — приятный бонус
Здравствуйте, Дарней, Вы писали:
Д>Здравствуйте, Сергей Губанов, Вы писали:
СГ>>Понимаетели, Вы привели случай, когда чужой модуль использует Ваш модуль: "импорт функций из моего модуля". А надо наоборот. Вы используете чей-то чужой УЖЕ написанный модуль и Вам надо в этот чужой уже написанный модуль как-то передать свою функцию обратного вызова (call-back function). Если в языке нет процедурных переменных (указателей на функцию), то сделать это Вы не сможете.
Д>Совершенно очевидно, что если модуль УЖЕ написан и УЖЕ использует каки-то фичи моего модуля, то избавиться от этих фич не получится. Но это к НАШЕМУ вопросу не относится.
Он был написан до того как Вы написали свой модуль и, значит, он о Вашем модуле ничего не знает, так понятно?
Как ему использовать Ваш модуль если нет call back function?
Здравствуйте, Дарней, Вы писали:
Д>Здравствуйте, WWL, Вы писали:
WWL>>Здесь не может быть циклических ссылок между компонентами системы. WWL>>Сергей и говорит Вам о том, что указатель на функцию — это "страховка" для одного модуля гарантированно вызывать функции, которые "ещё не написаны" (виртуальность).
Д>Никакие циклические ссылки здесь не нужны. Нужна всего лишь одна хорошо известная функция в каждом модуле.
Здравствуйте, VladD2, Вы писали:
VD>Моежт сам таки запонишь и не будшь потом рассказывать, что в Яве или Шарпе переменная — это указатель?
Ссылка отличается от указателя тем, что она совершенно прозрачна для программиста. Указатель можно проверить на NIL, а ссылку нельзя проверить на NIL, так как любое обращение к ссылке полностью равноценно обращению к самому объекту на который она ссылается. Вы просто используете термин "ссылка" обзывая им указатели в Java и в C#.
Еще раз про ссылку:
TYPE
MyRecord = RECORD
x: INTEGER;
....
(* куча всего, так что размер этой записи очень большой *)
...
END;
PROCEDURE Proc(VAR t: MyRecord);
BEGIN(* t - это ссылка на переменную типа MyRecord, нельзя написать: IF t # NIL THEN *)
t.x := 10;
...
END Proc;
Переменная типа MyRecord занимает много места в памяти, для того чтобы передать ее по быстрому в процедуру можно не копировать ее, а передать по ссылке
TYPE
ValueType = RECORD
a: PointerType;
b: ReferenceType;
END;
ReferenceType = POINTER TO RECORD
a: PointerType;
b: ReferenceType;
c: ValueType;
END;
PointerType = POINTER TO ValueType;
В С# или в Java основным является ReferenceType = POINTER TO RECORD. А, видимо, из аналогий с Си++, Вы посчитали, что PointerType = POINTER TO ValueType; есть что-то опасное, хотя это не имеет отношения к адресам и управляется сборщиком мусора и абсолютно безопасно. В C# и Java есть value-type и есть refernce-type, а в Обероне в добавок к этому еще есть совершенно безопасный управляемый сборщиком мусора pointer-type. Кстати, из-за того что pointer-type нет в C#, там ввели такой изврат как Boxing/Unboxing.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Он был написан до того как Вы написали свой модуль и, значит, он о Вашем модуле ничего не знает, так понятно?
Поясняю еще раз — для тех, кто в танке.
Рассмотрим на примере — COM, вариант с in-proc сервером. Когда нужно создать некий ком-объект, ОС загружает соответствующую DLL и вызывает у нее функцию DllGetClassObject, чтобы получить объект класса и через него создать экзмепляр нужного типа.
При этом совершенно очевидно, что ОС не знает НИЧЕГО о том, как устроен данный модуль DLL — и не может знать. Но откуда же она знает, что нужно вызывать именно эту функцию? Потому что разработчики приняли соответствующее СОГЛАШЕНИЕ.
Я не думаю, что в Обероне используется какой-то принципиально иной способ.
Скажу честно — я офигеваю все больше и больше. Еще что-то непонятно? Или мне нужно еще объяснить, что такое COM и компонентное программирование вообще?
Здравствуйте, Дарней, Вы писали:
Д>Поясняю еще раз — для тех, кто в танке. Д>Рассмотрим на примере — COM, вариант с in-proc сервером. Когда нужно создать некий ком-объект, ОС загружает соответствующую DLL и вызывает у нее функцию DllGetClassObject,
О, кстати, а давайте еще проще! Вот есть DLL в которой есть процедура. Что Вы делаете когда ее динамически загружаете? Как Вы вытаскиваете из DLL процедуру? Правильно, Вы вытаскиваете не саму процедуру, а лишь только получаете ее адрес. Вот Вам и процедурная переменная. То есть без процедурных переменных (указателей на функции), даже DLL динамически загрузить нельзя.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>О, кстати, а давайте еще проще! Вот есть DLL в которой есть процедура. Что Вы делаете когда ее динамически загружаете? Как Вы вытаскиваете из DLL процедуру? Правильно, Вы вытаскиваете не саму процедуру, а лишь только получаете ее адрес. Вот Вам и процедурная переменная. То есть без процедурных переменных (указателей на функции), даже DLL динамически загрузить нельзя.
Если мы говорим про ЯВУ, то там это не является обязательным — указатели на функции могут быть скрыты где-то глубоко внутри реализации. Мы просто имеем некий оператор, который сам загружает DLL и получает из нее нужный для НЕГО указатель. А другой оператор использует тот самый указатель, чтобы вызвать функцию и через нее — какой-то метод в модуле.
Именно так сделано в вышеупомянутом COM. Клиентскому коду знать что-либо о DllGetClassObject просто не нужно.
Надеюсь, мне не нужно рассказывать — что такое отделение интерфейса от реализации и зачем это нужно?
Здравствуйте, Дарней, Вы писали:
Д>Если мы говорим про ЯВУ, то там это не является обязательным — указатели на функции могут быть скрыты где-то глубоко внутри реализации. Мы просто имеем некий оператор, который сам загружает DLL и получает из нее нужный для НЕГО указатель. А другой оператор использует тот самый указатель, чтобы вызвать функцию и через нее — какой-то метод в модуле. Д>Именно так сделано в вышеупомянутом COM. Клиентскому коду знать что-либо о DllGetClassObject просто не нужно.
Ладно, пусть это было скрыто....
Теперь Вы можете вызывать любую процедуру из загруженной DLL. Но сама DLL не может вызывать Ваши процедуры. Вы ее можете, а она Ваши не может. Так вот с помощью процедурных переменных можно сделать так, чтобы и загруженная Вами DLL тоже могла вызывать Ваши процедуры. Чтоб симметрично было.
Здравствуйте, Кодт, Вы писали:
К>Null — это дефолтное значение объекта.
Точнее, это не значение объекта, а это значение переменной (указательного или ссылочного типа) которая может быть связана с объектом, а может быть не связана — то есть быть равной null.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Теперь Вы можете вызывать любую процедуру из загруженной DLL. Но сама DLL не может вызывать Ваши процедуры. Вы ее можете, а она Ваши не может. Так вот с помощью процедурных переменных можно сделать так, чтобы и загруженная Вами DLL тоже могла вызывать Ваши процедуры. Чтоб симметрично было.
Вот скажи мне ты с СОМ дело имел или только название слышал?
... << RSDN@Home 1.1.4 rev. 185 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Теперь Вы можете вызывать любую процедуру из загруженной DLL. Но сама DLL не может вызывать Ваши процедуры. Вы ее можете, а она Ваши не может. Так вот с помощью процедурных переменных можно сделать так, чтобы и загруженная Вами DLL тоже могла вызывать Ваши процедуры. Чтоб симметрично было.
Если она тоже будет следовать принятым соглашениям, то сможет — никаких принципиальных проблем я здесь не вижу.
С# тоже прекрасно обходится делегатами Только не надо говорить, что это те же самые указатели на функции — на самом деле это совсем другая вещь. Хотя где-то внутри указатели вероятно используются.