Здравствуйте, rrsstio, Вы писали:
R>Что общего между интерфейсом и делегатом
"Delegates and interfaces are similar in that they enable the separation of specification and implementation."
(c) MSDN
Здравствуйте, c-smile, Вы писали:
R>>Что общего между интерфейсом и делегатом
CS>Хороший вопрос. Автору — пять баллов.
CS>delegate (как тип) это такой interface который имеет единственный метод. CS>Т.е ответ на вопрос: делегат это разновидность интерфейса.
Корректнее было бы сказать, что делегат как и интерфейс используются для описания "контракта".
Т.к. формально (с точки зрения .NET) делегат это не интерфейс.
Здравствуйте, c-smile, Вы писали:
CS>С++ например.
CS>Функторы — т.е. объекты с определенным operator() фактически и есть интерфейсы-делегаты. CS>Нечто типа:
CS>
скорее это довольно неудачная попытка эмуляции делегата
К тому же я спрашивал именно про языки с формальной поддержкой интерфейсов/делегатов на уровне языка (в С++ ни того ни другого нет).
Предлагаю не начинать очередную ветку типа является ли С++ функциональным языком
CS>Спор closures они или нет еще не окончен как я понимаю. CS>В момент образования closure C# генерирует объект класса (object, sic!) в котором содержится snapshot значений используемых переменных окружения на момент образования closure. CS>В Python или JavaScript closure отличается тем что closure содержит ссылку на список call frames.
CS>Попробуй вот этот документ загрузить в browser: CS>
CS><html>
CS> <script>
CS> function A()
CS> {
CS> var a = 28;
CS> function B() { a += 32; }
CS> function C() { return a; }
CS> return [B,C];
CS> }
CS> var v = A();
CS> v[0]();
CS> var r = v[1]();
CS> alert(r);
CS> </script>
CS><body></body>
CS></html>
CS>Должен сказать 60. CS>В С# аналогичная конструкция должна сказать 28 (насколько я понимаю).
Неверное предположение:
class Program
{
private static void A(out Action B, out Func<int> C)
{
var a = 28;
B = () => { a += 32; };
C = () => a;
}
static void Main(string[] args)
{
Action B;
Func<int> C;
A(out B, out C);
B();
var r = C();
}
}
Здравствуйте, Curufinwe, Вы писали:
C>Здравствуйте, c-smile, Вы писали:
R>>>Что общего между интерфейсом и делегатом
CS>>Хороший вопрос. Автору — пять баллов.
CS>>delegate (как тип) это такой interface который имеет единственный метод. CS>>Т.е ответ на вопрос: делегат это разновидность интерфейса.
C>Корректнее было бы сказать, что делегат как и интерфейс используются для описания "контракта". C>Т.к. формально (с точки зрения .NET) делегат это не интерфейс.
Вопрос не специфицировал среду/язык. Делегаты есть во многих языках/средах.
С точки зрения языков в которых есть абстаркция делегатов delegate instance есть tuple:
object/method-ref. object может быть optional — вырожденный случай function reference.
interface instance есть тоже tuple: object/vtbl(список функций). В случае когда интерфейс состоит
из одной функции имеем vtbl состящую из одной функции т.е. фактически object/method-ref.
ЧТД.
Для интересующихся: в языке D делегатом также может быть ссылка на вложенную функцию. В этом случае образование
делегата этой функции это создание closure — object в том tuple это какскад stack frames — т.е. функция видит
локальные переменные обрамляющей функции. Вот такие вот пироги.
Здравствуйте, Curufinwe, Вы писали:
C>P.S. возвращаясь к теории: то, что делегаты сходны по сути с однометодными интерфейсами понятно, но есть ли языки, в которых делегат формально или синтаксически являются интерфейсами?
С++ например.
Функторы — т.е. объекты с определенным operator() фактически и есть интерфейсы-делегаты.
Нечто типа:
Спор closures они или нет еще не окончен как я понимаю.
В момент образования closure C# генерирует объект класса (object, sic!) в котором содержится snapshot значений используемых переменных окружения на момент образования closure.
В Python или JavaScript closure отличается тем что closure содержит ссылку на список call frames.
Попробуй вот этот документ загрузить в browser:
<html>
<script>
function A()
{
var a = 28;
function B() { a += 32; }
function C() { return a; }
return [B,C];
}
var v = A();
v[0]();
var r = v[1]();
alert(r);
</script>
<body></body>
</html>
Должен сказать 60.
В С# аналогичная конструкция должна сказать 28 (насколько я понимаю).
Здравствуйте, c-smile, Вы писали:
CS>Зато хорошо что замыкание быстро образуется (в JS).
CS>Хорошо что пременная освобождается в C#, но плохо что высокие накладные расходы (compile time, code size и время исполнения)
Что то мне подсказывает, что быстро в JS, это невыносимо медленно в C#
CS>Это проблема и С# и D кстати.
Нет таких проблем в C#
... << RSDN@Home 1.2.0 alpha 3 rev. 883 on Windows Vista 6.0.6001.65536>>
Здравствуйте, IB, Вы писали:
IB>Здравствуйте, rrsstio, Вы писали:
R>>Что общего между интерфейсом и делегатом IB>"Delegates and interfaces are similar in that they enable the separation of specification and implementation." IB>(c) MSDN
interface в программированнии и в широком смысле есть спецификация (или "контракт" как справедливо заметил Curufinwe) некоего набора
методов доступа к объекту. delegate это спецификация одного метода доступа — т.е. фактически интрфейса состоящего из одного метода.
Т.е. делегат есть частный случай интерфейса, т.е. delegate is-a interface в философическом смысле этого слова (вопрос был задан в "Философии", а не в ".NET")
Здравствуйте, c-smile, Вы писали:
CS>interface в программированнии и в широком смысле есть спецификация (или "контракт" как справедливо заметил Curufinwe) некоего набора CS>методов доступа к объекту.
В программировании, широком смысле, то что ты имеешь ввиду (спецификация некоего набора методов доступа к объекту), называется "публичный контракт". interface же — частный случай публичного контракта выраженный в терминах конкретного языка или группы языков, в данном случае — .Net
Иногда, слово интерфейс употребляют в смысле "публичный контракт", но так как вопрос был задан про NET, а там у понятия interface есть своя собственная трактовка и конкретная физическая реализация, то употреблять его в качестве синонима термину "публичный контракт", как минимум не корректно.
К тому же в вопросе слово интерфейс упоминалось вовсе не в "философском" смысле.
CS>Т.е. делегат есть частный случай интерфейса, т.е. delegate is-a interface в философическом смысле этого слова (вопрос был задан в "Философии", а не в ".NET")
Философский смысл слова интерфейс называется "публичный контракт".
P. S.
А я то здесь причем? В философском смысле и Net-овский интерфейс и делегат позволяют отделить описание сущности от ее реализации, что собственно и написано в MSDN. И, заметь, в этом определении нет не интерфейсов, ни контрактов.. ))
Здравствуйте, c-smile, Вы писали:
L>>Плохо что не освобождается. CS>Зато хорошо что замыкание быстро образуется (в JS).
CS>Хорошо что пременная освобождается в C#, но плохо что высокие накладные расходы (compile time, code size и время исполнения)
Говорить о высоких накладных расхода C#-а на фоне js — хм, это даже не смешно.
Здравствуйте, c-smile, Вы писали:
L>>Речь вроде как о скорости работы кода, а не о том у кого тяжелее рантайм.
CS>А ты специфицируй задачу время выполнения которой для тебя важно. Тогда и будем говорить. CS>Утверждать абстрактно что C# быстрее JS это technical nonsense.
Посмотри выше по ветке. Вопрос там вполе себе "специфицирован"
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, c-smile, Вы писали:
L>>>Речь вроде как о скорости работы кода, а не о том у кого тяжелее рантайм.
CS>>А ты специфицируй задачу время выполнения которой для тебя важно. Тогда и будем говорить. CS>>Утверждать абстрактно что C# быстрее JS это technical nonsense.
L>Посмотри выше по ветке. Вопрос там вполе себе "специфицирован"
Что интересует-то конкретно? Что быстрее обращение к stack variables или обращение к object member?
В JS (и в python и в lua) первое быстрее значительно. В .NET я так понимаю тоже stack variable доступна быстрее.
Сравнение же что быстрее JS или C# как я уже сказал корректно только с в конкретном контескте/задаче.
Здравствуйте, Curufinwe, Вы писали:
C>Здравствуйте, c-smile, Вы писали:
CS>>Зато хорошо что замыкание быстро образуется (в JS).
C>Где то была демонстрация на Silverlight — программа игры в шахматы. И там есть прикольный режим, когда можно заставить играть движок на .NET против javascript. Разница в количестве просчитанных за ед. времени ходов, как ни странно на порядок лучше у С#
CS>>Хорошо что пременная освобождается в C#, но плохо что высокие накладные расходы (compile time, code size и время исполнения) CS>>Так на так выходит.
C>Любая "реальная" программа на С# будет в разы быстрее интерпретируемых языков. C>сompile time — ни разу не проблема для С# — это же не С++
Есть ли разница в следующих фразах:
1) замыкания в JavaScript исполняются быстрее чем .NET, особенно JScript.NET очень это быстро делает.
2) текущий способ замыкания в JavaScript эффективнее способа используемого в C# (если бы его использовать в JS).
Я дико извиняюсь, или у меня уже с мыслеизъявлением на русском языке проблемы либо у
сторонников .NET наличествует некий комплекс перманентной вины что ли. Просто не знаю как это назвать.
Здравствуйте, c-smile, Вы писали:
C>>Корректнее было бы сказать, что делегат как и интерфейс используются для описания "контракта". C>>Т.к. формально (с точки зрения .NET) делегат это не интерфейс.
CS>Вопрос не специфицировал среду/язык. Делегаты есть во многих языках/средах.
Теоретически наверно так и есть, но могу поспорить, что имелся в виду .NET
Поэтому, чтобы уберечь автора вопроса от конфуза на след. интервью на позицию С# программиста я и написал:
формально (с точки зрения .NET)
P.S. возвращаясь к теории: то, что делегаты сходны по сути с однометодными интерфейсами понятно, но есть ли языки, в которых делегат формально или синтаксически являются интерфейсами?
Здравствуйте, c-smile, Вы писали:
CS>В момент образования closure C# генерирует объект класса (object, sic!) в котором содержится snapshot значений используемых переменных окружения на момент образования closure.
Нет там никакого снапшота. Если локальная переменная используется внутри замыкания, она с самого начала хранится в этом самом специальном объекте, в том числе и до запуска метода с замыканием.
... << RSDN@Home 1.2.0 alpha 3 rev. 883 on Windows Vista 6.0.6001.65536>>
Здравствуйте, c-smile, Вы писали:
CS>Спор closures они или нет еще не окончен как я понимаю. CS>В момент образования closure C# генерирует объект класса (object, sic!) в котором содержится snapshot значений используемых переменных окружения на момент образования closure. CS>В Python или JavaScript closure отличается тем что closure содержит ссылку на список call frames.
Значит ли это, что никакая локальная переменная этого call frame-а не будет доступна для сборщика мусора?
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, c-smile, Вы писали:
CS>>Спор closures они или нет еще не окончен как я понимаю. CS>>В момент образования closure C# генерирует объект класса (object, sic!) в котором содержится snapshot значений используемых переменных окружения на момент образования closure. CS>>В Python или JavaScript closure отличается тем что closure содержит ссылку на список call frames.
L>Значит ли это, что никакая локальная переменная этого call frame-а не будет доступна для сборщика мусора?
Что значит "не будет доступна"? GC всегда сканирует stack и heap ...
В tiscript например при обработке байткода BC_CLOSE (образование closure) происходит вызов:
который снимает call frames (execution environment) со стека и перемещает их в heap — т.е.
несколько функций вложенных в один и тот же родитель "шарят" один единственный набор переменных родителя.
В принципе в tiscript (и в Python и в JavaScript) на этом можно строить достаточно нетривиальные конструкции.
Например вот объект с strictly private переменными:
function MyObjFactory()
{
var m_one = 1;
var m_two = 2;
return {
getOne: function() { return m_one; },
setOne: function(v) { m_one = v; }
};
}
var obj = MyObjFactory();
obj.setOne( 3 ); // другого способа изменить m_one нет!
Здравствуйте, Curufinwe, Вы писали:
CS>>Должен сказать 60. CS>>В С# аналогичная конструкция должна сказать 28 (насколько я понимаю).
C>Неверное предположение:
C>
C>class Program
C> {
C> private static void A(out Action B, out Func<int> C)
C> {
C> var a = 28;
C> B = () => { a += 32; };
C> C = () => a;
C> }
C> static void Main(string[] args)
C> {
C> Action B;
C> Func<int> C;
C> A(out B, out C);
C> B();
C> var r = C();
C> }
C> }
C>
C>, даёт r = 60;
Это тогда означает что фактически конструкция:
private static void A(out Action B, out Func<int> C)
{
var a = 28;
B = () => { a += 32; };
C = () => a;
}
должна компилятором трансформируется в:
private static void A(out delegate void B(), out delegate int C())
{
class _tempC
{
var a = 28;
void B () { a += 32; }
int C () { return a; }
}
var _temp = new _tempC();
B = _temp.B;
C = _temp.C;
}
Я правильно понимаю? Т.е. вместо набора переменных на стеке он(компилятор) должен образовать класс, его instance и два делегата (interface slice) от методов этого инстанса.
То же самое можно воспроизвести в C++. Никто не говорит что C++ поддерживает functional нотацию — там это можно сделать но "руками".
Вопрос в личных предпочтениях — кто-то предпочитает писать с понятием как оно унутре устроено, а кому-то достаточно высокоуровневых конструкций (которые имеют свою цену).
Здравствуйте, c-smile, Вы писали:
CS>Что значит "доступна для сборщика мусора"? Если это означает "Может ли GC освободить эту переменную?" то ответ "нет"
Здравствуйте, c-smile, Вы писали:
CS>То же самое можно воспроизвести в C++. Никто не говорит что C++ поддерживает functional нотацию — там это можно сделать но "руками".
Так вот "поддерживает" — это когда не надо "можно сделать но "руками""
CS>Вопрос в личных предпочтениях — кто-то предпочитает писать с понятием как оно унутре устроено, а кому-то достаточно высокоуровневых конструкций (которые имеют свою цену).
Я выбираю третий путь — высокоуровневые конструкции + понимание, как оно "унутре".
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, c-smile, Вы писали:
CS>>Что значит "доступна для сборщика мусора"? Если это означает "Может ли GC освободить эту переменную?" то ответ "нет"
L>Спасибо. Плохо.
Что именно "Плохо"?
Плохо что C# для того чтобы сделать замыкание нужно создать класс, его инстанс и уже от него делегат?
Или плохо что call frame как он есть перемещается в heap (в JS)?
Здравствуйте, c-smile, Вы писали:
CS>>>Что значит "доступна для сборщика мусора"? Если это означает "Может ли GC освободить эту переменную?" то ответ "нет"
L>>Спасибо. Плохо.
CS>Что именно "Плохо"?
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, c-smile, Вы писали:
CS>>То же самое можно воспроизвести в C++. Никто не говорит что C++ поддерживает functional нотацию — там это можно сделать но "руками".
L>Так вот "поддерживает" — это когда не надо "можно сделать но "руками""
Философский вопрос про то что означает слово "поддерживает".
CS>>Вопрос в личных предпочтениях — кто-то предпочитает писать с понятием как оно унутре устроено, а кому-то достаточно высокоуровневых конструкций (которые имеют свою цену).
L>Я выбираю третий путь — высокоуровневые конструкции + понимание, как оно "унутре".
Ну дык выясняется что народ не сильно отдает отчет цене высокоуровневых конструкций. Из-за как раз недопонимания.
Начальный вопрос у автора как раз и возник (как я понимаю) от недопонимания физического устройства interface и delegate.
Хочется верить что наша плодотворная (имхо) дискуссия и поможет в этом разобраться.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, c-smile, Вы писали:
CS>>>>Что значит "доступна для сборщика мусора"? Если это означает "Может ли GC освободить эту переменную?" то ответ "нет"
L>>>Спасибо. Плохо.
CS>>Что именно "Плохо"?
L>Плохо что не освобождается.
Зато хорошо что замыкание быстро образуется (в JS).
Хорошо что пременная освобождается в C#, но плохо что высокие накладные расходы (compile time, code size и время исполнения)
Так на так выходит.
Проблема в том что такого рода высокоуровневые фичи при внешней простоте (использования) раздувают откомпилированный код.
Это проблема и С# и D кстати. На процессорах с небольшим instruction cache — проблемы.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, c-smile, Вы писали:
L>>>Плохо что не освобождается. CS>>Зато хорошо что замыкание быстро образуется (в JS).
CS>>Хорошо что пременная освобождается в C#, но плохо что высокие накладные расходы (compile time, code size и время исполнения)
L>Говорить о высоких накладных расхода C#-а на фоне js — хм, это даже не смешно.
Абсолютно не факт
hello.js:
WScript.Echo( "Hello world using JS!" ) ;
hello.cs:
using System;
class MainApp {
public static void Main()
{
Console.WriteLine("Hello World using C#!");
}
}
Зуб даешь что откомпилораванный hello.cs (exe) исполнится быстрее чем hello.js (вместе с запуском WSH)?
JS это фактически клей между вызовами native code. Т.е. есть задачи/опреции в которых JS может выигрывать у C#/.NET
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, c-smile, Вы писали:
CS>>Зуб даешь что откомпилораванный hello.cs (exe) исполнится быстрее чем hello.js (вместе с запуском WSH)?
L>Речь вроде как о скорости работы кода, а не о том у кого тяжелее рантайм.
А ты специфицируй задачу время выполнения которой для тебя важно. Тогда и будем говорить.
Утверждать абстрактно что C# быстрее JS это technical nonsense.
Скажем я был бы осторожен утверждая что следующий JS код:
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, c-smile, Вы писали:
CS>>А ты специфицируй задачу время выполнения которой для тебя важно.
AVK>Тут же вроде замыкания обсуждались, не так ли? Так на каком коде собственно замыкания в JS будут быстрее?
Образование замыкания в JS это копирование одной области памяти в другую. Фактически memcpy. Обращение к переменным из outer frame
функции — по индексу т.е. быстро. Если же делать как C# c образованием объекта и доступа к variables по ключам (object == hash map) то будет (в JS) медленнее, иногда значительнее.
Я так думаю что и в C# обращение к переменным на стеке (или в heap call frame если такое есть) по идее быстрее чем обращение к instance members некоего объекта ибо доп. косвенность.
Здравствуйте, c-smile, Вы писали:
CS>Это тогда означает что фактически конструкция:
CS>
CS>private static void A(out Action B, out Func<int> C)
CS>{
CS> var a = 28;
CS> B = () => { a += 32; };
CS> C = () => a;
CS>}
CS>
CS>должна компилятором трансформируется в:
CS>
CS>private static void A(out delegate void B(), out delegate int C())
CS>{
CS> class _tempC
CS> {
CS> var a = 28;
CS> void B () { a += 32; }
CS> int C () { return a; }
CS> }
CS> var _temp = new _tempC();
CS> B = _temp.B;
CS> C = _temp.C;
CS>}
CS>
Примерно так.
CS>Я правильно понимаю? Т.е. вместо набора переменных на стеке он(компилятор) должен образовать класс, его instance и два делегата (interface slice) от методов этого инстанса.
Какие могут быть переменные на стеке . Возможно если делегаты используются только внутри породившей их функции то да. В общем случае экземпляры делегатов могут хранится и передаваться и использоваться где угодно. Используя их в другом потоке вы тоже собираетесь только стеком обойтись.
В не зависимости от языка — для полноценного closure необходимо сохранять используемоё в нём "окружение" на стеке (как впрочем и для любого другого типа данных с состоянием).
CS>То же самое можно воспроизвести в C++. Никто не говорит что C++ поддерживает functional нотацию — там это можно сделать но "руками". CS>Вопрос в личных предпочтениях — кто-то предпочитает писать с понятием как оно унутре устроено, а кому-то достаточно высокоуровневых конструкций (которые имеют свою цену).
А ещё можно то же самое на С или asm реализовать. И секономить десяток процентов производительности за счёт увеличения размера и сложности программы в несколько раз.
Здравствуйте, c-smile, Вы писали:
CS>Ну дык выясняется что народ не сильно отдает отчет цене высокоуровневых конструкций. Из-за как раз недопонимания. CS>Начальный вопрос у автора как раз и возник (как я понимаю) от недопонимания физического устройства interface и delegate. CS>Хочется верить что наша плодотворная (имхо) дискуссия и поможет в этом разобраться.
Я думаю, что тема уже далеко ушла (как это часто бывает) от первоначального вопроса автора
Здравствуйте, c-smile, Вы писали:
CS>Зато хорошо что замыкание быстро образуется (в JS).
Где то была демонстрация на Silverlight — программа игры в шахматы. И там есть прикольный режим, когда можно заставить играть движок на .NET против javascript. Разница в количестве просчитанных за ед. времени ходов, как ни странно на порядок лучше у С#
CS>Хорошо что пременная освобождается в C#, но плохо что высокие накладные расходы (compile time, code size и время исполнения) CS>Так на так выходит.
Любая "реальная" программа на С# будет в разы быстрее интерпретируемых языков.
сompile time — ни разу не проблема для С# — это же не С++
Здравствуйте, c-smile, Вы писали:
CS>Есть ли разница в следующих фразах: CS>1) замыкания в JavaScript исполняются быстрее чем .NET, особенно JScript.NET очень это быстро делает. CS>2) текущий способ замыкания в JavaScript эффективнее способа используемого в C# (если бы его использовать в JS).
CS>Я дико извиняюсь, или у меня уже с мыслеизъявлением на русском языке проблемы либо у CS>сторонников .NET наличествует некий комплекс перманентной вины что ли. Просто не знаю как это назвать.
Я тоже дико извеняюсь, но то что вы расказали о реализации замыканий в JS нельзя назвать полноценным замыканием.
Подробности здесь
C>Какие могут быть переменные на стеке . Возможно если делегаты используются только внутри породившей их функции то да. В общем случае экземпляры делегатов могут хранится и передаваться и использоваться где угодно. Используя их в другом потоке вы тоже собираетесь только стеком обойтись.
1. В JS больше одного потока не бывает.
2. Никто не требует чтобы стек в JS был реализован на базе стека процессора. Стек может быть разбит на фреймы, которые можно отсоединять и сохранять в случае создания замыкания, реализовав систему подсчёта ссылок и/или сборку мусора.
3. Замыкания в JavaScript самые что ни на есть настоящие.
C>Я тоже дико извеняюсь, но то что вы расказали о реализации замыканий в JS нельзя назвать полноценным замыканием.
Правильно делаешь что извиняешься — замыкания в JS абсолютно полноценны.
Здравствуйте, Left2, Вы писали:
C>>Какие могут быть переменные на стеке . Возможно если делегаты используются только внутри породившей их функции то да. В общем случае экземпляры делегатов могут хранится и передаваться и использоваться где угодно. Используя их в другом потоке вы тоже собираетесь только стеком обойтись. L>1. В JS больше одного потока не бывает. L>2. Никто не требует чтобы стек в JS был реализован на базе стека процессора. Стек может быть разбит на фреймы, которые можно отсоединять и сохранять в случае создания замыкания, реализовав систему подсчёта ссылок и/или сборку мусора. L>3. Замыкания в JavaScript самые что ни на есть настоящие.
Отсюда выводы:
1. Реализация замыканий в JavaScript подходит только для JavaScript и возможно других скриптовых языков (т.к. не годится для многопоточной программы).
2. Стек в JavaScript — не "настоящий" . А значит утверждение о том, что замыкания с сохранением на стеке эффективней — неверно, т.к. сам "стек" в Javascript является аналогом .NET объекта в куче.
Возможно, я не прав — тогда интересно было бы узнать как можно реализовать полноценное замыкание в .NET без сохранения контекста замыкания в куче.
Здравствуйте, Left2, Вы писали:
C>>Я тоже дико извеняюсь, но то что вы расказали о реализации замыканий в JS нельзя назвать полноценным замыканием. L>Правильно делаешь что извиняешься — замыкания в JS абсолютно полноценны.
Я имел в виду способ реализации, а не сами замыкания.
Для JS (с его ограничениями и особенностями стека) они полноценны, но речь шла о сравнении реализаций JS и .NET.
Здравствуйте, Curufinwe, Вы писали:
C>Отсюда выводы:
C>1. Реализация замыканий в JavaScript подходит только для JavaScript и возможно других скриптовых языков (т.к. не годится для многопоточной программы).
Почему не подходит? Я не вижу разницы (с точки зрения многопоточности). call frame в heap (JS and others) и эмуляция его с исп. object и его members (C# way).
В чем ты видишь "неподхожесть"?
C>2. Стек в JavaScript — не "настоящий" . А значит утверждение о том, что замыкания с сохранением на стеке эффективней — неверно, т.к. сам "стек" в Javascript является аналогом .NET объекта в куче.
Стек самый что ни на есть настоящий. Стек растет только вершины (трюизм однако) т.е. динамической по размеру частью является только стек текующий функции.
Т.е. в момент образования замыкания мы все внешние frames можем смело перенести в heap — они в размерах меняться не будут. Т.е. банальное копирование и замена back references.
C>Возможно, я не прав — тогда интересно было бы узнать как можно реализовать полноценное замыкание в .NET без сохранения контекста замыкания в куче.
.NET ничем особым в этом плане не отличается. Два подхода: либо стек изначально размещать в куче либо перемещать его фрагменты в кучу когда надо.
Здравствуйте, Curufinwe, Вы писали:
CS>>Я правильно понимаю? Т.е. вместо набора переменных на стеке он(компилятор) должен образовать класс, его instance и два делегата (interface slice) от методов этого инстанса.
C>Какие могут быть переменные на стеке
"Здрастье, Настя!". Приехали. А где еще живут локальные переменные?
C>Возможно если делегаты используются только внутри породившей их функции то да. В общем случае экземпляры делегатов могут хранится и передаваться и использоваться где угодно. Используя их в другом потоке вы тоже собираетесь только стеком обойтись.
Смотри:
function A()
{
var a ;
function B()
{
var b;
}
}
В коде функции B стек может быть представлен связанным списком: собственно стек B (динамический масив с push pop) и ссылка на стек функции A что есть статический массив
с точки зрения кода B. Код исполняемый в B не может изменить размер стека A. Т.е. возможно построить систему в которой стек это обычный динамический массив который для каждого вызова функции свой. Эффективно это или нет — вопрос отдельный. Компилятор С# в принципе сие и исполняет создавая в heap объект с комплектом переменных для каждого вызова. Только он должен быть smart enough — не все внутренние функции приводят к замыканиям.
C>В не зависимости от языка — для полноценного closure необходимо сохранять используемоё в нём "окружение" на стеке (как впрочем и для любого другого типа данных с состоянием).
Что-то в этом утверждении не так.
CS>>То же самое можно воспроизвести в C++. Никто не говорит что C++ поддерживает functional нотацию — там это можно сделать но "руками". CS>>Вопрос в личных предпочтениях — кто-то предпочитает писать с понятием как оно унутре устроено, а кому-то достаточно высокоуровневых конструкций (которые имеют свою цену).
C>А ещё можно то же самое на С или asm реализовать. И секономить десяток процентов производительности за счёт увеличения размера и сложности программы в несколько раз.
Экономить на спичках может звучать дико только если ты не делаешь модель Кремля из спичек в масштабе 1:20.
Т.е. все зависит от задачи. В htmlayout например мне приходится считать стоимость каждой спички.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, c-smile, Вы писали:
CS>>Стек самый что ни на есть настоящий. Стек растет только вершины (трюизм однако)
AVK>Представь себе, куча в дотнете (за исключением LOH) — тоже.
Практически во всех GC средах так и происходит — memory allocation must be cheap.
А сказать-то ты чего хотел?
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, c-smile, Вы писали:
CS>>А сказать-то ты чего хотел?
AVK>Это намек на то, что никакого особого преимущества крутой стек JS не дает. Либо это нормальный стек без GC, либо то же самое, что управляемая куча.
А чем так крут-то JS стек?
Все дело в структуре call frame. Просто дополнительное поле NextEnvironment по которому достукиваются до outer variables.
NextEnvironment может указывать на что-то на стеке или на что-то в Heap (MovedEnvironment). Ничего сверхестественного в общем-то.
Компайлер при выработке байткода BC_EREF (достать переменную окружения) ставит номер фрейма от текущего и номер переменной в нём.
При исполнении BC_EREF соответсвенно разматывается список на глубину вложения и достается нужное значение.
Примерно то же самое и в .NET должно происходить (я имею ввиду косвенность доступа). Единственная разница в том что в .NET way локальные переменные внешней функции доступны через лишнюю косвенность (для неё самой). Что в общем-то наверное допустимый trade off. Усложняет компилятор — это да. А так "сканает" в общем-то.