Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Вопрос: ссылка на функцию

2 views
Skip to first unread message

Sergei Kozello

unread,
Aug 27, 2003, 2:51:13 PM8/27/03
to
Hi, All..

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.

Andrei N. Sobchuck

unread,
Aug 28, 2003, 2:12:42 AM8/28/03
to
Sergei Kozello <Sergei....@p38.f27.n5023.z2.fidonet.org> wrote:
SK> а в других нет (Java).

Там другой механизм - 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

Alexander Gribanov

unread,
Aug 29, 2003, 3:56:37 PM8/29/03
to
Hi, Sergei !

Однажды, 27 Авг 03 в 23:51, Sergei Kozello писал All:

SK> Hачал я размышлять почему в одних языках есть ссылка на функцию
SK> (Pascal, C++), а в других нет (Java). И вообще зачем она нужна.
Callback-функции? Асинхронный вызов процедур?

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

Hе прощаюсь, Alexander Gribanov.

Sergei Kozello

unread,
Aug 31, 2003, 8:10:17 AM8/31/03
to
Hi, Alexander..

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.

Alexei Vasiliev

unread,
Sep 1, 2003, 2:56:22 PM9/1/03
to
Я приветствую тебя, Alexander!

═══[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 ║_/\_/\_║
∙──┬──┬─══І══[ (-<+>-)=]══І══─┬──┬──∙
* ^ ■ ╘══╛ ╘══╛ ■ ^ *
──────────────────────────────────────────────────────────────
Парадокс изобретателя: "более общую проблему обычно решить проще".

Alex Cvetkov

unread,
Sep 3, 2003, 2:58:20 PM9/3/03
to
Hello Sergei!

31 Авг 03 17:10, Sergei Kozello писал(ла) Alexander Gribanov:

AG>> P.S.: Может кто-то начнет говорить, что можно передать вместо

AG>> ссылки на функцию ссылку на объект, порожденный от какого-нибудь
AG>> базового класса, в котором будет определен соответствующий метод.
AG>> Тогда встречный вопрос - а чем хуже прямая ссылка на функцию?..
SK> ИМХО, и тот, и другой способ имеют право на существование...
SK> Вот собственно и хотелось бы узнать, почему в той же Java ссылку на
SK> функцию убрали из языка. Ведь чем-то они это обосновали.

Java way больше похож на OOP

Alex Cvetkov

Anton Moscal

unread,
Sep 4, 2003, 4:51:11 AM9/4/03
to
Hello, Sergei!

You wrote to Alexander Gribanov on Sun, 31 Aug 2003 16:10:17 +0400:

AG>> класса, в котором будет определен соответствующий метод. Тогда
AG>> встречный вопрос - а чем хуже прямая ссылка на функцию?..

SK> ИМХО, и тот, и другой способ имеют право на существование...


SK> Вот собственно и хотелось бы узнать, почему в той же Java ссылку на
SK> функцию убрали из языка.

SK> Ведь чем-то они это обосновали.

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

Антон

Andrei N. Sobchuck

unread,
Sep 4, 2003, 5:52:23 AM9/4/03
to
Anton Moscal <m...@mail.tepkom.ru> wrote:
AM> классы и замыкания, которые фактически служат для имитации процедурных
AM> значений.

А где в Яве замыкания?


--
Андрей Собчук
and...@itware.com.ua

Anton Moscal

unread,
Sep 4, 2003, 6:03:15 AM9/4/03
to
Hello, Andrei!
You wrote to "Anton Moscal" <m...@mail.tepkom.ru> on Thu, 4 Sep 2003 09:52:23
+0000 (UTC):

AM>> классы и замыкания, которые фактически служат для имитации

AM>> процедурных значений.

ANS> А где в Яве замыкания?

Во вложенных анонимных классах - они имеют доступ ко всем final-переменным
из объемлющей функции. По реализации - именно замыкание.

Anton


Sergei Kozello

unread,
Sep 4, 2003, 2:11:51 PM9/4/03
to
Hi, 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.

Andrei N. Sobchuck

unread,
Sep 5, 2003, 1:55:24 AM9/5/03
to
Sergei Kozello <Sergei....@p38.f27.n5023.z2.fidonet.org> wrote:
SK> А можно узнать, что такое замыкание?

Это комбинация из _функции/процедуры_ и _среды_. _Среда_ - это
набор именованых переменных. Эти переменные _не_ декларируются внутри
функции и, по-этому, называются свободными. Название "замыкание" дано
потому что оно "замыкает" определёную среду, "захватывая" ссылки на
свободные переменные.

Пример:
Определён класс "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

Anton Moscal

unread,
Sep 5, 2003, 6:12:55 AM9/5/03
to
Hello, Sergei!
You wrote to Anton Moscal on Thu, 04 Sep 2003 22:11:51 +0400:

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


Sergei Kozello

unread,
Sep 5, 2003, 2:47:08 PM9/5/03
to
Hi, Andrei..

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.

Andrei N. Sobchuck

unread,
Sep 6, 2003, 6:49:22 AM9/6/03
to
Sergei Kozello <Sergei....@p38.f27.n5023.z2.fidonet.org> wrote:
SK> public void closure( int incr ) {
SK> i += incr;
SK> }


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

Anton Moscal

unread,
Sep 6, 2003, 7:53:38 AM9/6/03
to
Sat Sep 06 2003 14:49, Andrei N. Sobchuck wrote to Sergei Kozello:

SK>> Или правильней будет:

ANS> Почти. Замыкания имеют доступ к локальным переменным метода
ANS> в котором они созданы на чтение и запись. В Java же - только чтение.
ANS> Так что внутренние классы - не полные замыкания.

На самом деле не вполне так. Замыкание - понятие из функциональных языков, в
которых переменных в общем-то нет. Скажем в ML замыкание тожедественно по
реализации Java: в блок памяти копируются значения имен, образующих замыкание.


Но дело в том, что поскольку перменных нет - нет и проблемы (точнее переменные
есть - это ref, но как раз они реализуются как _константные_ ссылки на
изменяемые объекты - аналгом в Яве будет стандартный workaround - превратить
переменную в массив из одного элемента)

Антон

Andrei N. Sobchuck

unread,
Sep 6, 2003, 8:44:15 AM9/6/03
to
Anton Moscal <m...@mail.tepkom.ru> wrote:
AM> На самом деле не вполне так. Замыкание - понятие из функциональных языков, в
AM> которых переменных в общем-то нет. Скажем в ML замыкание тожедественно по
AM> реализации Java: в блок памяти копируются значения имен, образующих замыкание.

Что тогда означает термин "полное (full) замыкание"? "Неполное" (не раз
встречал по отношению к Яве)?

AM> Но дело в том, что поскольку перменных нет - нет и проблемы (точнее переменные
AM> есть - это ref, но как раз они реализуются как _константные_ ссылки на
AM> изменяемые объекты - аналгом в Яве будет стандартный workaround - превратить
AM> переменную в массив из одного элемента)

afaik, "внутри" так же работают и блоки в VisualWorks ST. Только "концы"
наружу не торчат.

btw, термин "замыкание" использовался сразу или появился попозже?

--
Андрей Собчук
and...@itware.com.ua

Anton Moscal

unread,
Sep 7, 2003, 3:08:37 PM9/7/03
to
Sat Sep 06 2003 16:44, Andrei N. Sobchuck wrote to "Anton Moscal":

ANS> btw, термин "замыкание" использовался сразу или появился попозже?

Насколько я знаю - сразу. Еще в Лиспе.

Антон

Sergei Kozello

unread,
Sep 9, 2003, 7:48:14 AM9/9/03
to
Hi, Anton..

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.

Sergei Kozello

unread,
Sep 9, 2003, 7:54:12 AM9/9/03
to
Hi, Andrei..

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.

alexey kolesnichenko

unread,
Sep 9, 2003, 10:55:00 AM9/9/03
to
dra til helvete, Sergei.

* quoting a message from Sergei Kozello to Anton Moscal:

SK> Я плохо знаком с C++, не знаешь ли ты плохого тона использования этих
SK> самых указателей на функции.
SK> Такого использования, что, посмотрев на код, думаешь, что лучше бы их не
SK> было. %)

да оно так и есть: пока опишешь указатель на функцию с приличным числом
параметров -- поседеть можно с непривычки. :)

t.w.a.s.k.

Andrei N. Sobchuck

unread,
Sep 10, 2003, 3:27:06 AM9/10/03
to
Sergei Kozello <Sergei....@p38.f27.n5023.z2.fidonet.org> wrote:
AS>> При помощи разных подходов удобно строить разные конструкции. При
AS>> помощи замыканий (в функциональных языках они называются лямбды, в
AS>> Смоллтолк - блоки, в Яве (с ограничением) - анонимные внутренние
AS>> классы) удобно выражать такие алгоритмы, которые не имеют состояния,
AS>> как, например, map (в Смоллток - collect: )

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

Vladimir Pavlikov

unread,
Sep 10, 2003, 7:49:46 AM9/10/03
to
Hello, alexey!

You wrote to Sergei Kozello on Tue, 09 Sep 2003 18:55:00 +0400:

SK>> Я плохо знаком с C++, не знаешь ли ты плохого тона использования этих
SK>> самых указателей на функции.
SK>> Такого использования, что, посмотрев на код, думаешь, что лучше бы их не
SK>> было. %)

ak> да оно так и есть: пока опишешь указатель на функцию с приличным числом
ak> параметров -- поседеть можно с непривычки. :)

Указатель отличается от самой функции наличием (* и ), обрамляющими
ее имя. Если седеть от такой малости, лучше и проще ходить лысым :)

With best regards, Vladimir Pavlikov. E-mail: p...@soil.msu.ru

--

Roman Dawydkin

unread,
Sep 11, 2003, 12:08:26 AM9/11/03
to
[Tue 09-Sep-2003 16:48] Sergei Kozello ==> Anton Moscal

SK> По сути дела начало казаться, что Ява бы ничего не потеряла, если бы в
SK> ней существовали указатели на функции - только писанины стало бы меньше
SK> (не надо было бы заключать эту функцию в класс).

Это всё переливание из пустого в порожнее...
В ООП и в Java нет функций. Точка. Поэтому не может быть и указателей на
функцию. Есть объекты, которые обмениваются сообщениями (посредством методов).
Это просто так есть. Может, ООП и плохая идеология (это отдельный вопрос), но
жить в ней можно только так. А если не хочется так жить -- перейти на
что-нибудь другое, напрмер ФП.
К тому же, указатели на фунцию менее универсальные -- функция существует
только в одном экземпляре и её нельзя инициализировать при создании
какими-нибудь внутренним состоянием. Две и более функции не могут разделять
какие-либо внутрениие данные (без нарушения инкапсуляции).

... <air...@chat.ru>

Andrew Filonov

unread,
Sep 11, 2003, 3:10:45 AM9/11/03
to
>>>>> "RD" == Roman Dawydkin writes:

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

Andrei N. Sobchuck

unread,
Sep 11, 2003, 5:27:40 AM9/11/03
to
Andrew Filonov <a...@antar.bryansk.ru> wrote:
RD>> функцию. Есть объекты, которые обмениваются сообщениями
RD>> (посредством методов). Это просто так есть.
AF> Какие именно объекты обмениваются сообщениями, при вызове
AF> статического метода, не требующего параметров?

Ни в одном "чистом" ОО языке нет статических методов ;)

--
Андрей Собчук
and...@itware.com.ua

Anton Moscal

unread,
Sep 11, 2003, 6:07:20 AM9/11/03
to
Hello, Andrei!
You wrote to Andrew Filonov <a...@antar.bryansk.ru> on Thu, 11 Sep 2003
09:27:40 +0000 (UTC):

AF>> Какие именно объекты обмениваются сообщениями, при вызове
AF>> статического метода, не требующего параметров?

ANS> Ни в одном "чистом" ОО языке нет статических методов ;)

В Smalltalk есть. Просто они называются "методы класса".

Anton


Andrew Filonov

unread,
Sep 11, 2003, 6:53:51 AM9/11/03
to
>>>>> "ANS" == Andrei N Sobchuck writes:

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.

Andrei N. Sobchuck

unread,
Sep 11, 2003, 7:01:08 AM9/11/03
to
Anton Moscal <m...@mail.tepkom.ru> wrote:

AF>>> Какие именно объекты обмениваются сообщениями, при вызове
AF>>> статического метода, не требующего параметров?

ANS>> Ни в одном "чистом" ОО языке нет статических методов ;)

AM> В Smalltalk есть. Просто они называются "методы класса".

Это не статические методы, а именно "методы класса" (как и сообщения -
не просто термин, а именно сообщения ;).
Они находятся в словаре методов метакласса соответсвующего классу.
Одним из признаков этого является их виртуальность. Из этих методов
доступны self и super (они ссылаются на класс-получатель сообщения).


--
Андрей Собчук
and...@itware.com.ua

Andrei N. Sobchuck

unread,
Sep 11, 2003, 7:13:41 AM9/11/03
to
Andrew Filonov <a...@antar.bryansk.ru> wrote:
AF>> Какие именно объекты обмениваются сообщениями, при вызове

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

AF>> статического метода, не требующего параметров?
ANS>> Ни в одном "чистом" ОО языке нет статических методов ;)

AF> Название непринципиально.

в даном случае - принципиально.

--
Андрей Собчук
and...@itware.com.ua

Anton Moscal

unread,
Sep 11, 2003, 4:48:23 PM9/11/03
to
Thu Sep 11 2003 09:08, Roman Dawydkin wrote to Sergei Kozello:

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

Антон

Sergei Kozello

unread,
Sep 11, 2003, 6:10:05 AM9/11/03
to
Hi, Roman..

Thursday September 11 2003 09:08, Roman Dawydkin wrote to Sergei Kozello:

SK>> По сути дела начало казаться, что Ява бы ничего не потеряла, если

SK>> бы в ней существовали указатели на функции - только писанины
RD> К тому же, указатели на фунцию менее универсальные -- функция
RD> существует только в одном экземпляре и её нельзя инициализировать при
RD> создании какими-нибудь внутренним состоянием. Две и более функции не
RD> могут разделять какие-либо внутрениие данные (без нарушения
RD> инкапсуляции).

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

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


Yours sincerely, Sergei Kozello.

Sergei Kozello

unread,
Sep 11, 2003, 5:55:19 AM9/11/03
to
Hi, Andrei..

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.

Sergei Kozello

unread,
Sep 11, 2003, 7:48:21 PM9/11/03
to
Hi, Anton..

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.

Andrei N. Sobchuck

unread,
Sep 12, 2003, 9:33:25 AM9/12/03
to
Sergei Kozello <Sergei....@p38.f27.n5023.z2.fidonet.org> wrote:

SK> Кстати, то что хотят сделать в 1.5 foreach - это и будет появление в Java
SK> внутренних итераторов?

foreach - это только малая часть возможных вариантов.

--
Андрей Собчук
and...@itware.com.ua

0 new messages