Hачал я размышлять почему в одних языках есть ссылка на функцию (Pascal, C++),
а в других нет (Java).
И вообще зачем она нужна.
Предположим есть программка (графический редактор), из которой пользователь
может
- выбором из списка указать текущую фигуру для рисования
- нажатием на кнопку рисовать выбранную фигуру
Рассмотрим реализации через ссылку на функцию и через наследование:
1. Ссылка на функцию
public
function Draw;
private
function DrawCircle;
function DrawRect;
// GUI
OnDraw() begin
Draw;
end;
OnSelect() begin
case n of
0: Draw := DrawCircle;
1: Draw := DrawRect;
end
end;
2. Hаследование
public abstract class Shape { public abstract void draw(); }
public class Circle extends Shape { public void draw(); }
public class Rect extends Shape { public void draw(); }
// GUI
public void paint() {
shape.draw();
}
public void select() {
shape = ShapeFactory.getShape( n );
}
В первом случае имеем всего по-минимуму, но с возрастанием количества фигур
работать, ИМХО, будет все менее
удобно из-за большого количества функций в одном месте.
Во втором случае имеем некоторый оверхед, но конструкция более гибка и
наглядна.
Вроде бы все говорит за то, что ссылка на функцию может быть заменена
проектированием иерархии классов.
Причем с более удобным дизайном.
Мне бы хотелось посоветоваться с вами, все ли я учитываю? Какие еще есть pro и
contra для ссылки на функцию.
Yours sincerely, Sergei Kozello.
Там другой механизм - inner classes.
SK> И вообще зачем она нужна.
Изменение поведения.
Например, есть сортированная коллекция. Если нужно изменить алгоритм
сортировки, то порождать на каждый случай новый подкласс непрактично.
Довольно подробно расписано тут:
http://jerry.cs.uiuc.edu/~plop/plop99/proceedings/sandu/sandu.pdf
SK> Вроде бы все говорит за то, что ссылка на функцию может быть заменена
SK> проектированием иерархии классов.
SK> Причем с более удобным дизайном.
http://wiki.cs.uiuc.edu/VisualWorks/How+to+get+rid+of+Objects+in+Smalltalk
--
Андрей Собчук
and...@itware.com.ua
Отправлено через сервер Форумы@mail.ru - http://talk.mail.ru
Однажды, 27 Авг 03 в 23:51, Sergei Kozello писал All:
SK> Hачал я размышлять почему в одних языках есть ссылка на функцию
SK> (Pascal, C++), а в других нет (Java). И вообще зачем она нужна.
Callback-функции? Асинхронный вызов процедур?
P.S.: Может кто-то начнет говорить, что можно передать вместо ссылки на функцию
ссылку на объект, порожденный от какого-нибудь базового класса, в котором будет
определен соответствующий метод. Тогда встречный вопрос - а чем хуже прямая
ссылка на функцию?..
Hе прощаюсь, Alexander Gribanov.
Saturday August 30 2003 00:56, Alexander Gribanov wrote to Sergei Kozello:
SK>> Hачал я размышлять почему в одних языках есть ссылка на функцию
SK>> (Pascal, C++), а в других нет (Java). И вообще зачем она нужна.
AG> Callback-функции? Асинхронный вызов процедур?
Я еще могу привести пример расширения функциональности - например, функции для
MathCAD так можно определять.
AG> P.S.: Может кто-то начнет говорить, что можно передать вместо ссылки
AG> на функцию ссылку на объект, порожденный от какого-нибудь базового
AG> класса, в котором будет определен соответствующий метод. Тогда
AG> встречный вопрос - а чем хуже прямая ссылка на функцию?..
ИМХО, и тот, и другой способ имеют право на существование...
Вот собственно и хотелось бы узнать, почему в той же Java ссылку на функцию
убрали из языка.
Ведь чем-то они это обосновали.
Yours sincerely, Sergei Kozello.
═══[30 Авг 03 00:56], Alexander Gribanov ══ Sergei Kozello:
SK>> Hачал я размышлять почему в одних языках есть ссылка на функцию
SK>> (Pascal, C++), а в других нет (Java). И вообще зачем она нужна.
AG> Callback-функции? Асинхронный вызов процедур?
AG> P.S.: Может кто-то начнет говорить, что можно передать вместо ссылки
AG> на функцию ссылку на объект, порожденный от какого-нибудь базового
AG> класса, в котором будет определен соответствующий метод. Тогда
AG> встречный вопрос - а чем хуже прямая ссылка на функцию?..
когда их больше одной ломает VMT заполнять, поэтому лучше сразу создать
EnvAgent и setAgent(EnvAgent*) и не заморачиваться. а еще желательно не забыть
туда первым методом version() поставить , на всякий случай :)
│ ___ │
av ║_/\_/\_║
∙──┬──┬─══І══[ (-<+>-)=]══І══─┬──┬──∙
* ^ ■ ╘══╛ ╘══╛ ■ ^ *
──────────────────────────────────────────────────────────────
Парадокс изобретателя: "более общую проблему обычно решить проще".
31 Авг 03 17:10, Sergei Kozello писал(ла) Alexander Gribanov:
AG>> P.S.: Может кто-то начнет говорить, что можно передать вместо
AG>> ссылки на функцию ссылку на объект, порожденный от какого-нибудь
AG>> базового класса, в котором будет определен соответствующий метод.
AG>> Тогда встречный вопрос - а чем хуже прямая ссылка на функцию?..
SK> ИМХО, и тот, и другой способ имеют право на существование...
SK> Вот собственно и хотелось бы узнать, почему в той же Java ссылку на
SK> функцию убрали из языка. Ведь чем-то они это обосновали.
Java way больше похож на OOP
Alex Cvetkov
AG>> класса, в котором будет определен соответствующий метод. Тогда
AG>> встречный вопрос - а чем хуже прямая ссылка на функцию?..
SK> ИМХО, и тот, и другой способ имеют право на существование...
SK> Вот собственно и хотелось бы узнать, почему в той же Java ссылку на
SK> функцию убрали из языка.
SK> Ведь чем-то они это обосновали.
Минимализмом. Но потом фактически признали ошибку, введя вложенные анонимные
классы и замыкания, которые фактически служат для имитации процедурных
значений.
Антон
А где в Яве замыкания?
--
Андрей Собчук
and...@itware.com.ua
AM>> классы и замыкания, которые фактически служат для имитации
AM>> процедурных значений.
ANS> А где в Яве замыкания?
Во вложенных анонимных классах - они имеют доступ ко всем final-переменным
из объемлющей функции. По реализации - именно замыкание.
Anton
Thursday September 04 2003 14:03, Anton Moscal wrote to Andrei N. Sobchuck:
AM>>> классы и замыкания, которые фактически служат для имитации
AM>>> процедурных значений.
ANS>> А где в Яве замыкания?
AM> Во вложенных анонимных классах - они имеют доступ ко всем
AM> final-переменным из объемлющей функции. По реализации - именно
AM> замыкание.
А можно узнать, что такое замыкание?
И как бы на примере выглядело использование подобного внутреннего класса с
помощью ссылки на функцию, а то я с трудом себе это представляю.
public class Test {
private int global;
public Test() { global = 456; }
public void proc() {
final int local = 11;
new Inner() {
public void write() {
System.out.println( "global=" + global );
System.out.println( "local=" + local );
}
}.write();
}
public static void main( String[] args ) {
new Test().proc();
}
}
abstract class Inner {
public Inner() {}
public abstract void write();
}
Yours sincerely, Sergei Kozello.
Это комбинация из _функции/процедуры_ и _среды_. _Среда_ - это
набор именованых переменных. Эти переменные _не_ декларируются внутри
функции и, по-этому, называются свободными. Название "замыкание" дано
потому что оно "замыкает" определёную среду, "захватывая" ссылки на
свободные переменные.
Пример:
Определён класс "TestClosure" с одной переменной "i".
В этом классе определим метод "closure" который создаёт и
возвращает замыкание.
TestClosure>>closure
^[ :incr | i := i + incr]
Переменная "incr" определена внутри замыкания (это параметр).
Переменная "i" является свободной.
Теперь:
| test closure | "Декларируем временные переменные"
test := TestClosure new. "Создаём экземпляр класса"
test i: 1. "Инициализируем переменную"
closure := test closure. "получаем замыкание, которое
содержит нашу переменную."
closure value: 3. "выполняем замыкание. Не смотря на то,
что мы не находимся в области видимости
объекта, замыкание изменяет значение
переменной. Будучи созданным в другом
экземпляре объекта, замыкание будет ссылатся
на переменные этого "другого" объекта."
test i "Получаем 4"
Кстати, по-сути, любой объект является замыканием.
Ведь он представляет собой набор функций, замыкающих
одну и ту же среду.
Замыкания появились задолго до того, как появились объекты.
--
Андрей Собчук
and...@itware.com.ua
SK> public void proc() {
SK> final int local = 11;
SK> new Inner() {
SK> public void write() {
SK> System.out.println( "global=" + global );
SK> System.out.println( "local=" + local );
SK> }
SK> }.write();
Мне как-то непонятен смысл этого примера - он ничем не отличается от просто
System.out.println( "global=" + global );
System.out.println( "local=" + local );
Если же речь идет о параметризации некоторого действия виртуальным методом -
то делается "в лоб":
do_something (fun () ->
printf "global=%d" global;
printf "local=%d" local
)
Anton
Friday September 05 2003 09:55, Andrei N. Sobchuck wrote to Sergei Kozello:
SK>> А можно узнать, что такое замыкание?
AS> Это комбинация из _функции/процедуры_ и _среды_. _Среда_ - это
AS> набор именованых переменных. Эти переменные _не_ декларируются внутри
AS> функции и, по-этому, называются свободными. Hазвание "замыкание" дано
AS> потому что оно "замыкает" определёную среду, "захватывая" ссылки на
AS> свободные переменные.
Хмм. Пытаюсь понять... Правильно ли назвать замыканием механизм инкапсуляции:
среда, которая включает переменные:
члены класса и методы класса, которые в общем случае не зависят от членов
класса.
Пример на Smalltalk? А то я язык не знаю, но по твоим комментариям вроде бы все
понятно. :)
AS> Пример:
AS> Определён класс "TestClosure" с одной переменной "i".
AS> В этом классе определим метод "closure" который создаёт и
AS> возвращает замыкание.
AS> TestClosure>>closure
AS> ^[ :incr | i := i + incr]
AS> Переменная "incr" определена внутри замыкания (это параметр).
AS> Переменная "i" является свободной.
AS> Теперь:
AS> | test closure | "Декларируем временные переменные"
AS> test := TestClosure new. "Создаём экземпляр класса"
AS> test i: 1. "Инициализируем переменную"
AS> closure := test closure. "получаем замыкание, которое
AS> содержит нашу переменную."
AS> closure value: 3. "выполняем замыкание. Hе смотря на то,
AS> что мы не находимся в области видимости
AS> объекта, замыкание изменяет значение
AS> переменной. Будучи созданным в другом
AS> экземпляре объекта, замыкание будет ссылатся
AS> на переменные этого "другого" объекта."
AS> test i "Получаем 4"
public class TestClosure {
private int i;
public void setI( int _i ) { i = _i; }
public int getI() { return i; }
public void closure( int incr ) {
i += incr;
}
public static void main() {
TestClosure test = new TestClosure();
test.setI( 1 );
test.closure();
assert( 4 == test.getI() );
}
}
Или правильней будет:
public Closure closure( final int incr ) {
return new Closure() {
public void run() { i += incr; }
};
}
public static void main() {
TestClosure test = new TestClosure();
test.setI( 1 );
Closure closure = test.closure( 3 );
closure.run();
assert( 4 = test.getI() );
}
А можно тогда узнать зачем применяются замыкания?
AS> Кстати, по-сути, любой объект является замыканием.
AS> Ведь он представляет собой набор функций, замыкающих
AS> одну и ту же среду.
Это как раз то, что я спросил в начале. Хотелось бы понять как соотносятся
фунциональность объектов и функциональность замыканий:
объекты расширают замыкания по функциональности или взаимооднозначны?
AS> Замыкания появились задолго до того, как появились объекты.
Ксати, я вот подумал, что замыкание пользуется доступом ко внутренним членам
другого класса, что ИМХО не есть хорошо - мы скрыли член класса, а тут он может
меняться в других местах и причем неявно. ИМХО, понимание программы
усложняется.
Т.е. я вроде бы выполняю метод одного класса (Closure), а он меняет переменную
класса TestClosure, причем с правом доступа private?
Когда данное поведение с неявным изменением членов класса необходимо, может
лучше сделать несколько сеттеров и сделать один evaluate() для установленных
переменных? Или функцией с несколькими параметрами?
Yours sincerely, Sergei Kozello.
SK> public static void main() {
SK> TestClosure test = new TestClosure();
SK> test.setI( 1 );
SK> test.closure();
Не так. Метод closure() должен вернуть _объект_, Который можно передать
как параметр в функцию. Или сохранить куда либо.
Чтобы реализовать такое поведение при помощи указателя на функцию нужно
совместно хранить указатель на функцию и ссылки на все переменные к которым
обращается функция. И при вызове этой функции передавать все как параметр.
SK> assert( 4 == test.getI() );
SK> }
SK> }
SK> Или правильней будет:
Почти. Замыкания имеют доступ к локальным переменным метода
в котором они созданы на чтение и запись. В Java же - только чтение.
Так что внутренние классы - не полные замыкания.
SK> public Closure closure( final int incr ) {
SK> return new Closure() {
SK> public void run() { i += incr; }
SK> };
SK> }
SK> public static void main() {
SK> TestClosure test = new TestClosure();
SK> test.setI( 1 );
SK> Closure closure = test.closure( 3 );
SK> closure.run();
Кстати, параметр должен быть не при создании замыкания,
а у метода run "closure.run( 4 ) ".
SK> assert( 4 = test.getI() );
SK> }
SK> А можно тогда узнать зачем применяются замыкания?
С замыканиями можно делать всё то, что и с указателями на функцию,
и даже больше.
AS>> Кстати, по-сути, любой объект является замыканием.
AS>> Ведь он представляет собой набор функций, замыкающих
AS>> одну и ту же среду.
SK> Это как раз то, что я спросил в начале. Хотелось бы понять как соотносятся
SK> фунциональность объектов и функциональность замыканий:
SK> объекты расширают замыкания по функциональности или взаимооднозначны?
Замыкание полностью эквивалентно объекту с одним методом.
Несколько замыканий, разделяющих одни и те же переменные, эквивалентны
объекту. Вроде бы так.
При помощи разных подходов удобно строить разные конструкции. При помощи
замыканий (в функциональных языках они называются лямбды, в Смоллтолк - блоки,
в Яве (с ограничением) - анонимные внутренние классы) удобно выражать такие
алгоритмы, которые не имеют состояния, как, например, map (в Смоллток -
collect: )
Те же внутренние итераторы - не возможно реализовать без замыканий. (Впрочем,
в Яве, афаик, и с ними очень затруднительно).
Кроме того, написание метода именно в том месте где он используется,
повышает читаемость, его легче написать, легче отладить.
Пример - сортировка. Можно создать несколько методов, сортирующих по
разным критериям. А можно, именно в точке использования этих методов
написать
aSortedCollection sortWith: [:a :b | a firstName < b firstName]
Тоже мелочь, а удобно (не в случае Явы, правда). Хотя в этом случае и
не нужно замыкание (нет обращения к свободным переменным).
В конце концов, возми любую книжку по яве и посмотри в каких
примерах используются анонимные внутренние классы.
--
Андрей Собчук
and...@itware.com.ua
SK>> Или правильней будет:
ANS> Почти. Замыкания имеют доступ к локальным переменным метода
ANS> в котором они созданы на чтение и запись. В Java же - только чтение.
ANS> Так что внутренние классы - не полные замыкания.
На самом деле не вполне так. Замыкание - понятие из функциональных языков, в
которых переменных в общем-то нет. Скажем в ML замыкание тожедественно по
реализации Java: в блок памяти копируются значения имен, образующих замыкание.
Но дело в том, что поскольку перменных нет - нет и проблемы (точнее переменные
есть - это ref, но как раз они реализуются как _константные_ ссылки на
изменяемые объекты - аналгом в Яве будет стандартный workaround - превратить
переменную в массив из одного элемента)
Антон
Что тогда означает термин "полное (full) замыкание"? "Неполное" (не раз
встречал по отношению к Яве)?
AM> Но дело в том, что поскольку перменных нет - нет и проблемы (точнее переменные
AM> есть - это ref, но как раз они реализуются как _константные_ ссылки на
AM> изменяемые объекты - аналгом в Яве будет стандартный workaround - превратить
AM> переменную в массив из одного элемента)
afaik, "внутри" так же работают и блоки в VisualWorks ST. Только "концы"
наружу не торчат.
btw, термин "замыкание" использовался сразу или появился попозже?
--
Андрей Собчук
and...@itware.com.ua
ANS> btw, термин "замыкание" использовался сразу или появился попозже?
Насколько я знаю - сразу. Еще в Лиспе.
Антон
Saturday September 06 2003 13:35, Anton Moscal wrote to Sergei Kozello:
AM> Вложенные классы - это вообще синтаксический сахар - виртуальная
AM> машина их не содержит (объемлющий класс просто является неявным
AM> параметром конструктора вложенного и запоминается в скрытом поле
AM> вложенного класса)
AM> Что же до анонимных классов - то там существенно еще как раз то, что
AM> он образует замыкание, а без этого замыкание придется расписывать явно
AM> передавая все необходимое параметрами конструктора.
AM> Другое дело, что без этого сахара все становится сяльно более
AM> громоздко.
Спасибо за объяснения.
По сути дела начало казаться, что Ява бы ничего не потеряла, если бы в ней
существовали указатели на функции - только писанины стало бы меньше (не надо
было бы заключать эту функцию в класс).
Может быть Sun посчитала, что указатели на функции могут быть опасны, если ими
злоупотреблять, как например переопределние операторов.
Я плохо знаком с C++, не знаешь ли ты плохого тона использования этих самых
указателей на функции.
Такого использования, что, посмотрев на код, думаешь, что лучше бы их не было.
%)
Yours sincerely, Sergei Kozello.
Saturday September 06 2003 14:49, Andrei N. Sobchuck wrote to Sergei Kozello:
AS> С замыканиями можно делать всё то, что и с указателями на функцию,
AS> и даже больше.
Спасибо за детальные объяснения.
Я вот вроде только диплом получил, казалось бы должен уже что-то уметь, а ведь
так не кажется:
читаю умные книжки, общаюсь в эхах и понимаю, что знаний почти нету и по сути
учиться я только начал. %)
AS> При помощи разных подходов удобно строить разные конструкции. При
AS> помощи замыканий (в функциональных языках они называются лямбды, в
AS> Смоллтолк - блоки, в Яве (с ограничением) - анонимные внутренние
AS> классы) удобно выражать такие алгоритмы, которые не имеют состояния,
AS> как, например, map (в Смоллток - collect: )
А можно по подробнее об этих алгоритмах, если речь идет об отображениях, то
правильно ли я понимаю, что речь идет об алгоритмах отображения key в value.
Разве там не просто массив связанных списков и алгоритмом является доступ к
i-му элементу, где i-хэш и дальнейший пробег по полученному списку?
AS> Те же внутренние итераторы - не возможно реализовать без замыканий.
AS> (Впрочем, в Яве, афаик, и с ними очень затруднительно).
Как я понял из исходников, то Collection, Set, Iterator - это представления
моделей List, Map.
Идеология MVC получается. Там эти представления получаются как из анонимных так
и из внутренних классов:
map.keySet().iterator(), list.iterator().
AS> Кроме того, написание метода именно в том месте где он используется,
AS> повышает читаемость, его легче написать, легче отладить.
AS> Пример - сортировка. Можно создать несколько методов, сортирующих по
AS> разным критериям. А можно, именно в точке использования этих методов
AS> написать
AS> aSortedCollection sortWith: [:a :b | a firstName < b firstName]
А как это читается: создать отсортированную коллекцию отсортировав по убыванию
по методу (или полю) firstName указанных объектов?
AS> Тоже мелочь, а удобно (не в случае Явы, правда). Хотя в этом случае и
AS> не нужно замыкание (нет обращения к свободным переменным).
В яве можно Collator или Comparator определить, правда для этого нужно
реализовать методы
compare(..) и equals(.) у всех сравниваемых объектов. :)
AS> В конце концов, возми любую книжку по яве и посмотри в каких
AS> примерах используются анонимные внутренние классы.
То что я видел и частично использовал - в основном обратные вызовы от
интерфейса, упрощенная параметризация
(например, определить run у потока и сразу запустить его), внутренние
итераторы. :)
Yours sincerely, Sergei Kozello.
* quoting a message from Sergei Kozello to Anton Moscal:
SK> Я плохо знаком с C++, не знаешь ли ты плохого тона использования этих
SK> самых указателей на функции.
SK> Такого использования, что, посмотрев на код, думаешь, что лучше бы их не
SK> было. %)
да оно так и есть: пока опишешь указатель на функцию с приличным числом
параметров -- поседеть можно с непривычки. :)
t.w.a.s.k.
SK> А можно по подробнее об этих алгоритмах, если речь идет об отображениях, то
SK> правильно ли я понимаю, что речь идет об алгоритмах отображения key в value.
collect: выполняет преобразование объектов. Напр.
persons collect: [ :each | each firstName ]
Вместо коллекции персон возвращает коллекцию из имён. Понятно, что запихнуть
туда можно алгоритм любой сложности. Но удобно пихать именно такие, из
пары вызовов.
AS>> Кроме того, написание метода именно в том месте где он используется,
AS>> повышает читаемость, его легче написать, легче отладить.
AS>> Пример - сортировка. Можно создать несколько методов, сортирующих по
AS>> разным критериям. А можно, именно в точке использования этих методов
AS>> написать
AS>> aSortedCollection sortWith: [:a :b | a firstName < b firstName]
SK> А как это читается: создать отсортированную коллекцию отсортировав по убыванию
SK> по методу (или полю) firstName указанных объектов?
*Пересортировать* по другому критерию (по firstName).
AS>> Тоже мелочь, а удобно (не в случае Явы, правда). Хотя в этом случае и
AS>> не нужно замыкание (нет обращения к свободным переменным).
SK> В яве можно Collator или Comparator определить, правда для этого нужно
SK> реализовать методы
SK> compare(..) и equals(.) у всех сравниваемых объектов. :)
Так отож.
AS>> В конце концов, возми любую книжку по яве и посмотри в каких
AS>> примерах используются анонимные внутренние классы.
SK> То что я видел и частично использовал - в основном обратные вызовы от
SK> интерфейса, упрощенная параметризация
SK> (например, определить run у потока и сразу запустить его), внутренние
SK> итераторы. :)
Если я не ошибаюсь, то в яве нет внутренних итераторов.
--
Андрей Собчук
and...@itware.com.ua
SK>> Я плохо знаком с C++, не знаешь ли ты плохого тона использования этих
SK>> самых указателей на функции.
SK>> Такого использования, что, посмотрев на код, думаешь, что лучше бы их не
SK>> было. %)
ak> да оно так и есть: пока опишешь указатель на функцию с приличным числом
ak> параметров -- поседеть можно с непривычки. :)
Указатель отличается от самой функции наличием (* и ), обрамляющими
ее имя. Если седеть от такой малости, лучше и проще ходить лысым :)
With best regards, Vladimir Pavlikov. E-mail: p...@soil.msu.ru
--
SK> По сути дела начало казаться, что Ява бы ничего не потеряла, если бы в
SK> ней существовали указатели на функции - только писанины стало бы меньше
SK> (не надо было бы заключать эту функцию в класс).
Это всё переливание из пустого в порожнее...
В ООП и в Java нет функций. Точка. Поэтому не может быть и указателей на
функцию. Есть объекты, которые обмениваются сообщениями (посредством методов).
Это просто так есть. Может, ООП и плохая идеология (это отдельный вопрос), но
жить в ней можно только так. А если не хочется так жить -- перейти на
что-нибудь другое, напрмер ФП.
К тому же, указатели на фунцию менее универсальные -- функция существует
только в одном экземпляре и её нельзя инициализировать при создании
какими-нибудь внутренним состоянием. Две и более функции не могут разделять
какие-либо внутрениие данные (без нарушения инкапсуляции).
... <air...@chat.ru>
RD> [Tue 09-Sep-2003 16:48] Sergei Kozello ==> Anton Moscal
SK> По сути дела начало казаться, что Ява бы ничего не потеряла, если
SK> бы в ней существовали указатели на функции - только писанины
SK> стало бы меньше (не надо было бы заключать эту функцию в класс).
RD> Это всё переливание из пустого в порожнее... В ООП и в Java
RD> нет функций. Точка. Поэтому не может быть и указателей на
RD> функцию. Есть объекты, которые обмениваются сообщениями
RD> (посредством методов). Это просто так есть.
Какие именно объекты обмениваются сообщениями, при вызове
статического метода, не требующего параметров?
RD> Может, ООП и плохая идеология (это отдельный вопрос), но жить в
RD> ней можно только так.
так жить нельзя ;-)
--
Andrew E. Filonov
1) You can't win
2) You can't break even
3) You can't even quit the game
Ни в одном "чистом" ОО языке нет статических методов ;)
--
Андрей Собчук
and...@itware.com.ua
AF>> Какие именно объекты обмениваются сообщениями, при вызове
AF>> статического метода, не требующего параметров?
ANS> Ни в одном "чистом" ОО языке нет статических методов ;)
В Smalltalk есть. Просто они называются "методы класса".
Anton
RD> функцию. Есть объекты, которые обмениваются сообщениями
RD> (посредством методов). Это просто так есть.
AF> Какие именно объекты обмениваются сообщениями, при вызове
AF> статического метода, не требующего параметров?
ANS> Ни в одном "чистом" ОО языке нет статических методов ;)
Название непринципиально.
--
Andrew E. Filonov
A carelessly planned project will take three times
longer than expected; a carefully planned project will
take only twice as long.
AF>>> Какие именно объекты обмениваются сообщениями, при вызове
AF>>> статического метода, не требующего параметров?
ANS>> Ни в одном "чистом" ОО языке нет статических методов ;)
AM> В Smalltalk есть. Просто они называются "методы класса".
Это не статические методы, а именно "методы класса" (как и сообщения -
не просто термин, а именно сообщения ;).
Они находятся в словаре методов метакласса соответсвующего классу.
Одним из признаков этого является их виртуальность. Из этих методов
доступны self и super (они ссылаются на класс-получатель сообщения).
--
Андрей Собчук
and...@itware.com.ua
Обмениваются действительно объекты. Получателем м.б. класс, в
языках где есть классы (ST) или просто объект если классов нет (Self)
AF>> статического метода, не требующего параметров?
ANS>> Ни в одном "чистом" ОО языке нет статических методов ;)
AF> Название непринципиально.
в даном случае - принципиально.
--
Андрей Собчук
and...@itware.com.ua
RD> К тому же, указатели на фунцию менее универсальные -- функция
RD> существует только в одном экземпляре и её нельзя инициализировать при
RD> создании какими-нибудь внутренним состоянием.
можно:
let counter =
let n = ref 0 in
fun () -> incr n; !n
for i = 1 to 10 do
printf "counter %d=%d\b" i (counter ())
done
напечатает понятно что.
RD> Две и более функции не
RD> могут разделять какие-либо внутрениие данные (без нарушения
RD> инкапсуляции).
Могут:
let (next_i, pred_i) =
let counter = ref 0 in
( (fun () -> incr counter; !counter).
(fun () -> decr counter; !counter)
)
let _ =
printf "%d\n" (next_i ());
printf "%d\n" (next_i ());
printf "%d\n" (prev_i ())
напечатает 1 2 1
Антон
Thursday September 11 2003 09:08, Roman Dawydkin wrote to Sergei Kozello:
SK>> По сути дела начало казаться, что Ява бы ничего не потеряла, если
SK>> бы в ней существовали указатели на функции - только писанины
RD> К тому же, указатели на фунцию менее универсальные -- функция
RD> существует только в одном экземпляре и её нельзя инициализировать при
RD> создании какими-нибудь внутренним состоянием. Две и более функции не
RD> могут разделять какие-либо внутрениие данные (без нарушения
RD> инкапсуляции).
Вот оно: если мы подменяем не один указатель на функцию, а сразу несколько.
Тут, думаю, и начнется головная боль. В объекте мы переопределим все нужные
функции, а если мы оперируем с разрозненными указателями, то что-то можно и
перепутать.
К тому же пара или больее функции получаются связанны только идейно и за их
целостное изменение отвечает целиком и польностью программист. В случае
объектов язык помогает программисту механизмами инкапсуляции. То что связанно -
то и находится вместе.
Yours sincerely, Sergei Kozello.
Wednesday September 10 2003 11:27, Andrei N. Sobchuck wrote to Sergei Kozello:
AS>>> При помощи разных подходов удобно строить разные конструкции.
AS>>> При помощи замыканий (в функциональных языках они называются
AS>>> лямбды, в Смоллтолк - блоки, в Яве (с ограничением) - анонимные
AS>>> внутренние классы) удобно выражать такие алгоритмы, которые не
AS>>> имеют состояния, как, например, map (в Смоллток - collect: )
AS> collect: выполняет преобразование объектов. Hапр.
AS> persons collect: [ :each | each firstName ]
AS> Вместо коллекции персон возвращает коллекцию из имён. Понятно, что
AS> запихнуть туда можно алгоритм любой сложности. Hо удобно пихать именно
AS> такие, из пары вызовов.
Весьма удобно! Я еще посмотрел, что в Смоллтоке можно сделать "фильтрацию":
persons select: [:each | each male = true]
Практически не применял, но выглядит удобнее чем условная проверка в цикле
итерирования на Java.
А внутри этой конструкции тот же итратор, только внутренний:
for ( Iterator i = persons.iterator(); i.hasNext(); ) // сюда бы фильтр
вставить. :)
{
Person person = (Person)persons.next();
if ( person.male )
{
// .. code
}
}
Производительность их одинакова?
AS>>> В конце концов, возми любую книжку по яве и посмотри в каких
AS>>> примерах используются анонимные внутренние классы.
SK>> То что я видел и частично использовал - в основном обратные
SK>> вызовы от интерфейса, упрощенная параметризация (например,
SK>> определить run у потока и сразу запустить его),
SK>> внутренние итераторы. :)
AS> Если я не ошибаюсь, то в яве нет внутренних итераторов.
Поздравляю себя, соврамши. :)
Я подумал, что под внутреннеми итераторами подразумевается вызов
list.iterator(), посмотрел сейчас по-внимательней, а это конструкция как в
примере, который я привел выше.
Кстати, то что хотят сделать в 1.5 foreach - это и будет появление в Java
внутренних итераторов?
Yours sincerely, Sergei Kozello.
Friday September 12 2003 00:48, Anton Moscal wrote to Roman Dawydkin:
RD>> К тому же, указатели на фунцию менее универсальные -- функция
RD>> существует только в одном экземпляре и её нельзя инициализировать
RD>> при создании какими-нибудь внутренним состоянием.
AM> можно:
AM> let counter =
AM> let n = ref 0 in
AM> fun () -> incr n; !n
AM> for i = 1 to 10 do
AM> printf "counter %d=%d\b" i (counter ())
AM> done
AM> напечатает понятно что.
Изящно! А можно поинтересоваться, что это за язык.
Так, кстати и в C можно:
int counter() {
static int n = 1;
return n++;
}
int main(int argc, char* argv[]) {
for ( int i = 1; i < 10; i++ ) {
printf( "counter %d=%d\n", i, counter() );
}
return 0;
}
Только одна беда: i c функцией связано неявно.
RD>> Две и более функции не
RD>> могут разделять какие-либо внутрениие данные (без нарушения
RD>> инкапсуляции).
АМ>Могут:
АМ> let (next_i, pred_i) =
АМ> let counter = ref 0 in
АМ> ( (fun () -> incr counter; !counter).
АМ> (fun () -> decr counter; !counter)
АМ> )
АМ> let _ =
АМ> printf "%d\n" (next_i ());
АМ> printf "%d\n" (next_i ());
АМ> printf "%d\n" (prev_i ())
АМ> напечатает 1 2 1
А как вот такое сотворить без классов в C и Java не знаю. %)
А каково практическое применение такого множественного определения функций с
общими переменными?
Предполагаю, что это переходный период от функций к классам?
Yours sincerely, Sergei Kozello.
SK> Кстати, то что хотят сделать в 1.5 foreach - это и будет появление в Java
SK> внутренних итераторов?
foreach - это только малая часть возможных вариантов.
--
Андрей Собчук
and...@itware.com.ua