Re[9]: Базовое отличие ООП от ФП
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.04.24 11:55
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>так объект можно сконструировать:

SP>
SP>const auto m = MyObject().setField1(1).setField2(2).setField3(3);
SP>

Простите, но это — чесание правой ногой левого уха. Если у меня заранее известны все нужные мне "поля" и их значения, то в разы удобнее пользоваться специализированным конструктором:
const auto m = MyObject(1, 2, 3);

Fluent-цепочки в основном нужны тогда, когда у меня есть многостадийное конструирование. Например, как-то так:
auto m_temp = MyObject().setField1(1).setField2(2);
const auto m = (conditional_expression) ? m_temp.setField3(17) : m_temp.setField4(42);
return m;


SP>Так на основе объекта создать клон с изменённым свойством


SP>
SP>const auto anotherObj = m.copy().setField1(10);
SP>

Офигеть как удобно! И, к тому же, error: 'const class MyObject' has no member named 'copy'
https://godbolt.org/z/ze57E31v9

SP>А что ещё надо?

Надо, чтобы а) всё работало и б) легко читалось и писалось.


SP>Ну да, immutable накладывает серьёзные ограничения на создание программ.

Не, это не immutable накладывает, а конкретно ваш подход — ужасен.
Даже оставаясь в рамках C++ и подобных ему императивных ОО-языков, иммутабельность можно реализовать значительно менее кошмарным способом.
Для примера можно посмотреть хотя бы на то, как устроены DateTime и TimeSpan в C#.

SP>Поэтому 90% писать на этом не могут и уходят. Но принципиальных препятствий нет. Тот ООП, который мы ненавидим любим, уже не сделаем с такими ограничениями, но то что сделаем меньшим ООП от этого не станет.

Конечно станет. Вы покажите мне пример кода на этом вашем "ООП", который выходит за пределы однострочного примера.
И мы с вами убедимся, что никакого ООП там нет, и что из кода все "объекты" можно безболезненно убрать, заменив их ADT.

SP>И говорить, что immutable является определяющим аттрибутом ФП, как по мне, тоже неправильно. Любая программа написанная в функциональном стиле имеет в глубине изменяемое состояние (те же регистры, вызовы библиотечных функций).

Регистры тут вообще нерелевантны. Современные языки программирования с регистрами не связаны примерно никак. А "вызовы библиотечных функций" обычно наоборот, не "в глубине", а "на поверхности". Чтобы сохранить основной граф вычислений чистым.

SP>Или вот мой любимый пример:


SP>
SP>fn main() {
SP>    let strings = vec!["tofu", "93", "18"];
SP>    let (numbers, errors): (Vec<_>, Vec<_>) = strings
SP>        .into_iter()
SP>        .map(|s| s.parse::<i32>())
SP>        .partition(Result::is_ok);
SP>    errors.map(|e| println!("Error: {0}", e););
SP>}
SP>


SP>Ну чем не функциональщина? Однако же изменяемое состояние тут есть (println или другая функция логирования).

Функциональщина не отказывается от изменяемого состояния. Она просто делает его как можно более явным. Я не знаю, что там по этому поводу думает Rust, но в строгих ФП-языках println — это "особенная" функция, которая помимо своего прямого аргумента принимает "вселенную до" и возвращает "вселенную после".
Кстати, вот в этом коде println — это метод какого объекта? Или это всё же не ООП?

SP>То же кеширование результатов функции является вроде как аттрибутом ФП, но строится на основе изменяемого сотояния (по-другому ну никак).

Нет, кеширование атрибутом ФП не является. Но вот его возможность является прямым следствием ФП.
Memoize можно применять не к любой функции. Например, к println — нельзя.
В идеале, такое ограничение должно выражаться прямо в языке — чтобы memoize(println) давало compile-time error. А не run-time error, и уж тем более не молчаливое неверное поведение.

SP>В общем призываю выделять immutable программирование в отдельную парадигму.

Нет там никакой отдельной парадигмы. Ну, разве что мы назовём отдельной парадигмой SSA-форму.
Но она настолько сурова, что на ней никто не пишет. Удобнее всё же иметь несколько больше возможностей по структурированию кода и данных, чем чистая SSA поверх скаляров.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Базовое отличие ООП от ФП
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.04.24 12:05
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>ООП это когда данные и функции объединяются в одну сущность.


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


vsb>Подходы друг с другом никак не пересекаются и одно другому никак не мешает.

Данные и функции можно объединять в одну сущность безо всякого ООП.
Вот простейший пример:

public static Func<int, int> AddX(int x) => (int y)=>y+x; 
public static int Add(int x, int y) => x+y;

public static Func<T2, R> FixX<T1, T2, R>(Func<T1, T2, R> f, T1 x) => (T2 y) => f(x, y);


public static int Main()
{
  var encapsulated = AddX(3); // объединили функцию и значение
  Console.WriteLine(encapsulated(42));
  
  var enc2 = FixX(Add, 5);  // объединили функцию и значение
  Console.WriteLine(enc2(17));
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Базовое отличие ООП от ФП
От: vsb Казахстан  
Дата: 03.04.24 15:38
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Данные и функции можно объединять в одну сущность безо всякого ООП.


Это уже пошла имитация ООП. С одной функцией ещё не так заметно, а если добавить несколько функций (к одному набору данных), то уже видно будет. Имитировать ФП через интерфейс с одной виртуальной функцией (как это сделано в Java) тоже можно. А на С можно имитировать и то и другое через указатели на функции. Суть в концепции, а не в конкретном механизме реализации.
Отредактировано 03.04.2024 15:39 vsb . Предыдущая версия . Еще …
Отредактировано 03.04.2024 15:39 vsb . Предыдущая версия .
Re[4]: Базовое отличие ООП от ФП
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.04.24 16:04
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Это уже пошла имитация ООП. С одной функцией ещё не так заметно, а если добавить несколько функций (к одному набору данных), то уже видно будет.

Да, я показывал.
Но "имитировать" классическое ООП, где "реакция" на "сообщение" зависит от предыстории, на честном неизменяемом ФП затруднительно.
Поэтому ООП — это не столько про "объединение функций и данных", сколько про представление решения в виде объектов, изменяющих своё состояние во времени.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Базовое отличие ООП от ФП
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 03.04.24 17:19
Оценка:
Здравствуйте, Sinclair, Вы писали:
Ну ООП это не только состояние. Но самое главное это наследование полей, свойств методов и их переопределение.
VMT! Интерфейсы! Видимость свойств и методов.
Ref тоже могут быть read only readonly ref

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

Вот в C# для структур нет наследования, хотя могли бы и завести тип структура с VMT как в C++
и солнце б утром не вставало, когда бы не было меня
Re[5]: Базовое отличие ООП от ФП
От: vsb Казахстан  
Дата: 04.04.24 02:52
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

vsb>>Это уже пошла имитация ООП. С одной функцией ещё не так заметно, а если добавить несколько функций (к одному набору данных), то уже видно будет.

S>Да, я показывал.
S>Но "имитировать" классическое ООП, где "реакция" на "сообщение" зависит от предыстории, на честном неизменяемом ФП затруднительно.

Неизменяемость на мой взгляд не является неотъемлемым признаком ФП. Это отдельная концепция. Которая, кстати, в некотором виде стала весьма популярна и в таком языке, как Java, где стали очень часто применять неизменяемые объекты.

ООП на неизменяемом ФП на мой взгляд это что-то вроде Erlang. Где каждый объект это функция, рекурсивно вызывающая сама себя с изменёнными параметрами (имитация цикла событий с мутабельным состоянием) и на каждой итерации принимающая объект и как-то его обрабатывающая (обработка вызова метода).
Re[10]: Базовое отличие ООП от ФП
От: Pauel Беларусь http://blogs.rsdn.org/ikemefula
Дата: 04.04.24 10:10
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pauel, Вы писали:

P>>Потому и полезно
S>Не вижу связи. Код-то на этом как писать?

Как я понимаю, это позволяет сделать нечто навроде initializer в C#
return new User()
   .withName('Коля')
   .withEmail('коля+2024@гемайл.ком')
   .withImage('data:image/png;base64,...')


И, поскольку, return m.with... не пролезет, то это вполне себе годное ограничение.

Это ж C++, тут на всё есть особый пример
Отредактировано 04.04.2024 10:13 Pauel . Предыдущая версия .
Re[11]: Базовое отличие ООП от ФП
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 04.04.24 10:17
Оценка: -1
Здравствуйте, Pauel, Вы писали:

P>>>Потому и полезно

S>>Не вижу связи. Код-то на этом как писать?

P>Как я понимаю, это позволяет сделать нечто навроде initializer в C#

P>
P>return new User()
P>   .withName('Коля')
P>   .withEmail('коля+2024@гемайл.ком')
P>   .withImage('data:image/png;base64,...')
P>


P>И, поскольку, return m.with... не пролезет, то это вполне себе годное ограничение.

А не проще через конструктор . Ведь readOnly тоже должны быть инициализированы! И конструктор без параметров должен быть запрещен!

Record structs в C#: эффективные и безопасные типы данных
и солнце б утром не вставало, когда бы не было меня
Re[6]: Базовое отличие ООП от ФП
От: Pauel Беларусь http://blogs.rsdn.org/ikemefula
Дата: 04.04.24 10:22
Оценка: +1
Здравствуйте, vsb, Вы писали:

vsb>Неизменяемость на мой взгляд не является неотъемлемым признаком ФП. Это отдельная концепция. Которая, кстати, в некотором виде стала весьма популярна и в таком языке, как Java, где стали очень часто применять неизменяемые объекты.


Неизменяемость это просто единственное условие где может работать ФП.
Намастырить пайплайн для обработки данных на мутабельных функциях очень даже можно, правда минорная ошибка порушит всю цивилизацию.
В свое время на Си и Ассемблере так и делали
— функция принимает указатель на список функций
— функция возвращает указатель на список функций
— функция из списка изменяет данные так и эдак

Тут есть одна сложность — доказать те или иные свойства пайпалайна в общем случае не представляется возможным. Зато в частном случае, если у вас есть десяток-другой отлаженых комбинаторов, можете использовать такое сколько влезет.
Re[12]: Базовое отличие ООП от ФП
От: Pauel Беларусь http://blogs.rsdn.org/ikemefula
Дата: 04.04.24 10:27
Оценка: :))
Здравствуйте, Serginio1, Вы писали:

P>>И, поскольку, return m.with... не пролезет, то это вполне себе годное ограничение.

S> А не проще через конструктор . Ведь readOnly тоже должны быть инициализированы! И конструктор без параметров должен быть запрещен!

При чем здесь проще? Речь о том, для чего можно использовать заявленную фичу.

Если выбирали такой дизайн по какой причине, то очевидно что readonly и запрет такого конструктора сюда не входит.
Re[12]: Базовое отличие ООП от ФП
От: sergii.p  
Дата: 04.04.24 10:31
Оценка:
Здравствуйте, Serginio1, Вы писали:

P>>
P>>return new User()
P>>   .withName('Коля')
P>>   .withEmail('коля+2024@гемайл.ком')
P>>   .withImage('data:image/png;base64,...')
P>>


S> А не проще через конструктор . Ведь readOnly тоже должны быть инициализированы! И конструктор без параметров должен быть запрещен!


например, нам не надо задавать email и картинку. А в конструкторе мы обязаны перечислить все параметры. Их там может быть 20 штук. И мы должны каждый явно указать. Неудобно.
Re[13]: Базовое отличие ООП от ФП
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 04.04.24 10:38
Оценка:
Здравствуйте, Pauel, Вы писали:

P>Здравствуйте, Serginio1, Вы писали:


P>>>И, поскольку, return m.with... не пролезет, то это вполне себе годное ограничение.

S>> А не проще через конструктор . Ведь readOnly тоже должны быть инициализированы! И конструктор без параметров должен быть запрещен!

P>При чем здесь проще? Речь о том, для чего можно использовать заявленную фичу.


P>Если выбирали такой дизайн по какой причине, то очевидно что readonly и запрет такого конструктора сюда не входит.

Выбирали такой дизайн криворукие дизайнеры. В шарпе сделали правильно.
и солнце б утром не вставало, когда бы не было меня
Re[13]: Базовое отличие ООП от ФП
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 04.04.24 10:44
Оценка:
Здравствуйте, sergii.p, Вы писали:

P>>>
P>>>return new User()
P>>>   .withName('Коля')
P>>>   .withEmail('коля+2024@гемайл.ком')
P>>>   .withImage('data:image/png;base64,...')
P>>>


S>> А не проще через конструктор . Ведь readOnly тоже должны быть инициализированы! И конструктор без параметров должен быть запрещен!


SP>например, нам не надо задавать email и картинку. А в конструкторе мы обязаны перечислить все параметры. Их там может быть 20 штук. И мы должны каждый явно указать. Неудобно.


В шарпе есть именованные параметры и параметры по умолчанию

Именованные и необязательные аргументы (Руководство по программированию на C#)

public void ExampleMethod(int required, string optionalstr = "default string",
    int optionalint = 10)

[q]
Если вы знаете имя третьего параметра, можете использовать для выполнения задачи именованный аргумент.


anExample.ExampleMethod(3, optionalint: 4);


Плюс такого подхода ты знаешь значения по умолчанию!
и солнце б утром не вставало, когда бы не было меня
Отредактировано 04.04.2024 11:03 Serginio1 . Предыдущая версия . Еще …
Отредактировано 04.04.2024 10:46 Serginio1 . Предыдущая версия .
Re[11]: Базовое отличие ООП от ФП
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.04.24 10:58
Оценка:
Здравствуйте, Pauel, Вы писали:
P>Как я понимаю, это позволяет сделать нечто навроде initializer в C#
P>
P>return new User()
P>   .withName('Коля')
P>   .withEmail('коля+2024@гемайл.ком')
P>   .withImage('data:image/png;base64,...')
P>

Это решаает какую-то проблему, которой нет.
P>Это ж C++, тут на всё есть особый пример
Ну, тогда хотелось бы релевантных примеров. Обещали показать immutable OOP, а показали какую-то убогую многостадийную инициализацию иммутабельных объектов.
Можно взять какую-то реалистичную задачу, для которой ООП подходит хорошо. Ну, там, реализацию оконного интерфейса.
Чтобы при включении checkbox1 у нас editbox1 становился enabled, а при выключении — disabled.
На ООП это работает отлично, хоть в наивной форме, хоть в продвинутых архитектурах вроде MVC/MVP/MVVM.
Как это устроено на ФП, я тоже отдалённо представляю.
А вот как это будет устроено на "иммутабельном ООП", хотелось бы посмотреть.
Ну, то есть у меня, конечно же, есть некоторые представления о том, как бы это выглядело; но они крайне далеки от конкретно этой реализации с &&.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Базовое отличие ООП от ФП
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.04.24 11:37
Оценка: +1
Здравствуйте, sergii.p, Вы писали:
SP>например, нам не надо задавать email и картинку. А в конструкторе мы обязаны перечислить все параметры. Их там может быть 20 штук. И мы должны каждый явно указать. Неудобно.
Никто не мешает нам иметь пяток конструкторов для типовых комбинаций начальных параметров. Никто не мешает нам использовать null object pattern для задания параметров, которые не нужны.
Ну и, самое главное — никто не мешает нам делать нормальную реализацию иммутабельных объектов, когда все set-методы возвращают копию объекта.
Это позволяет делать не только многостадийную инициализацию в одну строку, но и описывать произвольные функциональные зависимости.
Например, нетрудно строить всякие конвейеры в стиле
from d in _dates select d.AddDays(17).AddYears(-1);
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Базовое отличие ООП от ФП
От: Pauel Беларусь http://blogs.rsdn.org/ikemefula
Дата: 04.04.24 12:40
Оценка:
Здравствуйте, Serginio1, Вы писали:

P>>Если выбирали такой дизайн по какой причине, то очевидно что readonly и запрет такого конструктора сюда не входит.

S> Выбирали такой дизайн криворукие дизайнеры. В шарпе сделали правильно.

Что вы предлагаете, переписать с С++ на C# ради инициализаторов?

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

Form {
   header: {content: aaa} 
   main: { 
     list: [
      ItemA {id: 'a', content: yyy },
      ItemB {id: 'a', content: zzz },
    ]
   },
   footer: OkCancelFooter {onOk: onOkHandler, onCancel: onCancelHandler, onDispose: onDisposeHandler}
}


Глядишь, с таким инициализатором не пришлось бы городить огород типа XAML
Re[14]: Базовое отличие ООП от ФП
От: Pauel Беларусь http://blogs.rsdn.org/ikemefula
Дата: 04.04.24 12:51
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Никто не мешает нам иметь пяток конструкторов для типовых комбинаций начальных параметров. Никто не мешает нам использовать null object pattern для задания параметров, которые не нужны.


Пять конструкторов — это значит, что скорее всего в итоге невнятная документация и в коде будет мешанина, т.к. кто нибудь передаст null не туда.

Множественные перегрузки конструкторов или методов — это разве что в ДСЛ сгодится, а так лучше без всего этого обходиться.

S>Ну и, самое главное — никто не мешает нам делать нормальную реализацию иммутабельных объектов, когда все set-методы возвращают копию объекта.


мешает — гц. Всё таки дохловат в дотнете гц. Если плодить на каждый чих временные объекты, вы очень быстро раздуваете нулевое поколение и выходите за его пределы.

Если у вас есть промежутки, где гц может включиться, то это не проблема. Но вот всякие переинициализации в синхронном коде, да еще в цикле — у вас на ровном месте будет вылазить конское поглощение памяти. Подкинули 10 филдов, внезапно, это 10 клонов всей вашей кунсткамеры.
Для плоских объектов это еще куда ни шло. А если у вас на таком месте задается структура типа DOM, то вы ошалеете с такой иммутабельностью.
Re[12]: Базовое отличие ООП от ФП
От: Pauel Беларусь http://blogs.rsdn.org/ikemefula
Дата: 04.04.24 13:01
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А вот как это будет устроено на "иммутабельном ООП", хотелось бы посмотреть.

S>Ну, то есть у меня, конечно же, есть некоторые представления о том, как бы это выглядело; но они крайне далеки от конкретно этой реализации с &&.

В иммутабельном OOP это будет примерно так же, как делают лет 10 во фронтенде — redux + react.

Модель — каждое изменение, сколь угодно малое, дает вам новую иерархию, старую можно хранить для истории. Для этого глубокая древовидная структура годится слабо, нужна как можно более плоская модель.
Вьюшка — обновляется согласно модели — если ссылка на новый объект и на старый отличается, надо пересоздать все нижележащие элементы
Рутовый объект — мутабельный, запускает цикл обновление, в конце переприсваивает ссылки на новый UI и новую модель

Из недостатков — конский расход памяти, конский расход процессора, нужно знать как под капотом работает рендерер и подобные механизмы, итд. Иначе очень легко намастырить код, когда на каждый onchange наверху будет отжираться конский граф объектов
Собственно, большая часть туториалов по реакту это "вот так не надо, потому что унутре ... в итоге всё дохнет"

Повторить такой фокус для классических winforms точно не выйдет , и для xaml сильно вряд ли выйдет — эти вещи никогда не проектировались под подобное использование.
Re[15]: Базовое отличие ООП от ФП
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 04.04.24 13:34
Оценка:
Здравствуйте, Pauel, Вы писали:

P>Здравствуйте, Serginio1, Вы писали:


P>>>Если выбирали такой дизайн по какой причине, то очевидно что readonly и запрет такого конструктора сюда не входит.

S>> Выбирали такой дизайн криворукие дизайнеры. В шарпе сделали правильно.

P>Что вы предлагаете, переписать с С++ на C# ради инициализаторов?


Нет про конструкторы

Именованные и необязательные аргументы (Руководство по программированию на C#)

P>Тамошние инициализаторы, кстати говоря, довольно убогие.

P>Я бы предпочел инициализатор навроде такого

P>
P>Form {
P>   header: {content: aaa} 
P>   main: { 
P>     list: [
P>      ItemA {id: 'a', content: yyy },
P>      ItemB {id: 'a', content: zzz },
P>    ]
P>   },
P>   footer: OkCancelFooter {onOk: onOkHandler, onCancel: onCancelHandler, onDispose: onDisposeHandler}
P>} 
P>


P>Глядишь, с таким инициализатором не пришлось бы городить огород типа XAML


XAML это про декларативность. То есть за строкой скрывается куча кода.

Ну а в приведённом тобой коде это экономия на new.
и солнце б утром не вставало, когда бы не было меня
Re[15]: Базовое отличие ООП от ФП
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.04.24 13:35
Оценка:
Здравствуйте, Pauel, Вы писали:

P>Пять конструкторов — это значит, что скорее всего в итоге невнятная документация и в коде будет мешанина, т.к. кто нибудь передаст null не туда.

P>Множественные перегрузки конструкторов или методов — это разве что в ДСЛ сгодится, а так лучше без всего этого обходиться.
Это, скажем так, смелое утверждение.
Давайте возьмём более-менее любую популярную библиотеку и посмотрим, сколько конструкторов у привычных нам объектов.
Например, какой-нибудь FileStream. Или тот же DateTime.

S>>Ну и, самое главное — никто не мешает нам делать нормальную реализацию иммутабельных объектов, когда все set-методы возвращают копию объекта.

P>мешает — гц. Всё таки дохловат в дотнете гц. Если плодить на каждый чих временные объекты, вы очень быстро раздуваете нулевое поколение и выходите за его пределы.
Во-первых, речь шла не о дотнете, а о C++. Современные компиляторы C++ прекрасно устраняют лишние копирования в цепочках вроде m2 = m1.setField1(17).setField2(42).
Во-вторых, в дотнете иммутабельность прекрасно дружит с value-типами. Где джит тоже устраняет лишние копирования в цепочках модификаций.
P>Если у вас есть промежутки, где гц может включиться, то это не проблема. Но вот всякие переинициализации в синхронном коде, да еще в цикле — у вас на ровном месте будет вылазить конское поглощение памяти. Подкинули 10 филдов, внезапно, это 10 клонов всей вашей кунсткамеры.
P>Для плоских объектов это еще куда ни шло. А если у вас на таком месте задается структура типа DOM, то вы ошалеете с такой иммутабельностью.
В-третьих, для того и делаются перегрузки конструкторов — чтобы избегать цепочек бессмысленных копирований в среде, где нет escape analysis.
А в-четвёртых, если вы хотите посмотреть на приложение, в котором на таком месте задаётся структура типа DOM, то запустите Visual Studio.
Там весь редактор кода — это иммутабельное дерево поверх иммутабельного дерева.
И все инспекторы и codefix-провайдеры работают с этим иммутабельным деревом именно через всякие root.ReplaceNode(classDeclaration, classDeclaration.AddModifiers(items)).
Вполне себе всё это шустро работает, и GC им не мешает .
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.