Здравствуйте, c-smile, Вы писали:
CS>Кто-нибудь смотрел такой язык http://www.daovm.net/ ? CS>Впечатления?
Смесь луа и металуа ++ Автор отказался от минимализиа, но слегка увлекся в другую сторону, навалив туда все, о чем знал. Некоторые называют это "практический язык" . VM там от Lua, с незначительными (судя по результатам тестов) изменениями.
Здравствуйте, z00n, Вы писали:
Z>Смесь луа и металуа ++ Автор отказался от минимализиа, но слегка увлекся в другую сторону, навалив туда все, о чем знал. Некоторые называют это "практический язык" . VM там от Lua, с незначительными (судя по результатам тестов) изменениями.
Просто интересно, на основании чего сделано это заключение: "VM там от Lua" ?
Насколько я вижу как минимум object allocation сделано по типу Python — объекты выделяются с пом. malloc() т.е. в C heap.
+ reference counting с loop детектором. Что в общем-то упрощает жизнь при написании native functions но фрагментирует heap особенно в scripting use cases.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, z00n, Вы писали:
Z>>Смесь луа и металуа ++ Автор отказался от минимализиа, но слегка увлекся в другую сторону, навалив туда все, о чем знал. Некоторые называют это "практический язык" . VM там от Lua, с незначительными (судя по результатам тестов) изменениями.
CS>Просто интересно, на основании чего сделано это заключение: "VM там от Lua" ?
1) Автор часто светился в lua mailist
2) Он написал в об этом в FAQ.
In the begenning of 2006, the author was attracted and convinced by the design of the Lua 5 virtual machine, and started to design and implement the Dao interpreter as a new virtual machine with ideas inspired by the Lua virtual machine and its instruction set. Since then the language has also been re-designed under the name Dao.
3) Результаты тестов имеют паттерны, характерные для Lua VM, например относительно плохие результаты на binary_tree и meteor.
CS>Насколько я вижу как минимум object allocation сделано по типу Python — объекты выделяются с пом. malloc() т.е. в C heap. CS>+ reference counting с loop детектором. Что в общем-то упрощает жизнь при написании native functions но фрагментирует heap особенно в scripting use cases.
В луа они выделяются с помощью realloc, т.е. там же.
Здравствуйте, z00n, Вы писали:
CS>>Просто интересно, на основании чего сделано это заключение: "VM там от Lua" ? Z>
Z>In the begenning of 2006, the author was attracted and convinced by the design of the Lua 5 virtual machine, and started to design and implement the Dao interpreter as a new virtual machine with ideas inspired by the Lua virtual machine and its instruction set. Since then the language has also been re-designed under the name Dao.
Ага, понятно.
CS>>Насколько я вижу как минимум object allocation сделано по типу Python — объекты выделяются с пом. malloc() т.е. в C heap. CS>>+ reference counting с loop детектором. Что в общем-то упрощает жизнь при написании native functions но фрагментирует heap особенно в scripting use cases.
Z>В луа они выделяются с помощью realloc, т.е. там же.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, z00n, Вы писали:
CS>>>Насколько я вижу как минимум object allocation сделано по типу Python — объекты выделяются с пом. malloc() т.е. в C heap. CS>>>+ reference counting с loop детектором. Что в общем-то упрощает жизнь при написании native functions но фрагментирует heap особенно в scripting use cases.
Z>>В луа они выделяются с помощью realloc, т.е. там же.
CS>Как-то это все неправильно если честно.
С точки зрения луа — языка, который вместе со всеми своими библиотеками занимает 150K, и предназначен в первую очередь для встраивания — это OK. Если беспокоит фрагментация — весь интерфейс выделения памяти там выведен наружу и аллокатор при необходимости заменяется на custom.
С моей точки зрения у луа всего два серьезных недостатка: отсутствие встроенных туплов (хотя бы пар), и индексы начинаются с 1.
Здравствуйте, z00n, Вы писали:
CS>>Как-то это все неправильно если честно.
Z>С точки зрения луа — языка, который вместе со всеми своими библиотеками занимает 150K, и предназначен в первую очередь для встраивания — это OK. Если беспокоит фрагментация — весь интерфейс выделения памяти там выведен наружу и аллокатор при необходимости заменяется на custom.
Я честно говоря не совсем понимаю как внешний аллокатор может помочь.
Нормальный GC предполагает компактификацию памяти, т.е. например объекты могут перемещаться в heap в результате GC.
Z>С моей точки зрения у луа всего два серьезных недостатка: отсутствие встроенных туплов (хотя бы пар), и индексы начинаются с 1.
Умм... А чем в принципе tuple отличается от массива из двух элементов, скажем в JS:
Z>>С точки зрения луа — языка, который вместе со всеми своими библиотеками занимает 150K, и предназначен в первую очередь для встраивания — это OK. Если беспокоит фрагментация — весь интерфейс выделения памяти там выведен наружу и аллокатор при необходимости заменяется на custom.
CS>Я честно говоря не совсем понимаю как внешний аллокатор может помочь. CS>Нормальный GC предполагает компактификацию памяти, т.е. например объекты могут перемещаться в heap в результате GC.
Самый распостраненный способ бороться с фрагментацией это: http://en.wikipedia.org/wiki/Memory_pool — его-то луа и поддерживает.
Z>>С моей точки зрения у луа всего два серьезных недостатка: отсутствие встроенных туплов (хотя бы пар), и индексы начинаются с 1.
CS>Умм... А чем в принципе tuple отличается от массива из двух элементов, скажем в JS: CS>
CS>var tuple = [2,"second"];
CS>
Принципиальных отличий нет, но есть практические.
Tuple — это immutable fixed-size heterogenious array. Подразумевается, что он эффективный по памяти и очень быстрый, а иммутабельность дает кое-какие дополнительные гарантии. Array(или Hashtable) занимают больше памяти и медленнее — когда у вас этих псевдотуплов миллионы — начинает сказываться. Зачем нужны туплы в таком количестве? — строить из них иммутабельные структуры данных — есть задачи где это сильно упрощает жизнь.
Второе очевидное применение туплов — аргументы функций. У луа сейчас эту роль выполняет стэк — но он не первоклассная сущность — это плохо. Конкретно в луа этот стек порождает значимые скобки (coersion) и много ненужной расхлябанности, например:
local x,y = 1,2,3 -- correct in lua: 3 just gone
local x,y,z = 1,2 -- correct in lua: z == nil
Z>>>С точки зрения луа — языка, который вместе со всеми своими библиотеками занимает 150K, и предназначен в первую очередь для встраивания — это OK. Если беспокоит фрагментация — весь интерфейс выделения памяти там выведен наружу и аллокатор при необходимости заменяется на custom.
CS>>Я честно говоря не совсем понимаю как внешний аллокатор может помочь. CS>>Нормальный GC предполагает компактификацию памяти, т.е. например объекты могут перемещаться в heap в результате GC. Z>Самый распостраненный способ бороться с фрагментацией это: http://en.wikipedia.org/wiki/Memory_pool — его-то луа и поддерживает.
Самый распостраненный способ бороться с фрагментацией это GC насколько мне известно.
Z>>>С моей точки зрения у луа всего два серьезных недостатка: отсутствие встроенных туплов (хотя бы пар), и индексы начинаются с 1.
CS>>Умм... А чем в принципе tuple отличается от массива из двух элементов, скажем в JS: CS>>
CS>>var tuple = [2,"second"];
CS>>
Z>Принципиальных отличий нет, но есть практические. Z>Tuple — это immutable fixed-size heterogenious array. Подразумевается, что он эффективный по памяти и очень быстрый, а иммутабельность дает кое-какие дополнительные гарантии. Array(или Hashtable) занимают больше памяти и медленнее — когда у вас этих псевдотуплов миллионы — начинает сказываться. Зачем нужны туплы в таком количестве? — строить из них иммутабельные структуры данных — есть задачи где это сильно упрощает жизнь. Z>Второе очевидное применение туплов — аргументы функций. У луа сейчас эту роль выполняет стэк — но он не первоклассная сущность — это плохо. Конкретно в луа этот стек порождает значимые скобки (coersion) и много ненужной расхлябанности, например: Z>
Z>local x,y = 1,2,3 -- correct in lua: 3 just gone
Z>local x,y,z = 1,2 -- correct in lua: z == nil
Z>
А какой другой вариант multi-assignment? Как по другому это сделать?
Допустим что tuples образуются как (1,2,"three"). Т.е. получаем некий immutable array и трех элементов.
Тогда что должно происходить в этих случаях:
Буду признателен за примеры борьбы посредством GC (за исключением очевидных: "перешли на Java/C#/Erlang" ).
CS>А какой другой вариант multi-assignment? Как по другому это сделать?
CS>Допустим что tuples образуются как (1,2,"three"). Т.е. получаем некий immutable array и трех элементов. CS>Тогда что должно происходить в этих случаях: CS>
CS>local v = (1,2,3)
CS>
v — это тупл, им можно пользоваться как обычным значением. По видимому в языке (нашем, гипотетическом) есть синтаксис для доступа к отдельным элементам.
CS>
CS>local x,y,z = (1,2,3)
CS>
CS>и почему?
В языке не должно быть никакого "мультиприсваивания" — поэтому слева у вас по прежнему тупл, только анонимный. Все (ну или почти все) языки программирования с туплами, имеют синтаксический сахар, который позволяет пользоваться такой записью, но компилятор переписывает x,y,z как v$001._1 v$001._2 v$001._3. На самом деле это вырожденный случай паттерн-матчинга и вот такое например:
local x,y,z = (1,2)
... должно быть ошибкой даже в динамическом языке.
В идеале любая _запятая_ — конструктор тупла, поэтому аргументы мультиарных функций тоже туплы (ну а void это Unita любое значение это унарный тупл).
Здравствуйте, z00n, Вы писали:
Z>Здравствуйте, c-smile, Вы писали:
CS>>Самый распостраненный способ бороться с фрагментацией это GC насколько мне известно.
Z>Способ с GC не годится, например, для игровых приставок.
Честно говоря выбранный способ работы с памятью в JS в FireFox далек от оптимального решения. Выделять scripting objects в C heap это себя не любить. Насколько я знаю все остальные JS движки используют moving GCs в той или иной форме. Это кстати хорошо видно в Process Explorer — график выделения памяти. Почему-то мне казалось что Lua в этом смысле грамотнее сделан.
Z>Буду признателен за примеры борьбы посредством GC (за исключением очевидных: "перешли на Java/C#/Erlang" ).
Z>v — это тупл, им можно пользоваться как обычным значением. По видимому в языке (нашем, гипотетическом) есть синтаксис для доступа к отдельным элементам.
Дело в том что tuple это объект который аллоцируется в heap. В случае Lua который использует достаточно дорогой аллокатор (C malloc) генерация таких tuples будет весьма грустной.
Вот это вот в Lua (и в tiscript):
local x,y,z = 1,2,3
разворачивается в последоваетльность PUSH/POP/STORE(VAR) байткод-команд, т.е. на стеке — память вообще не аллоцируется.
CS>>
CS>>local x,y,z = (1,2,3)
CS>>
CS>>и почему?
Z>В языке не должно быть никакого "мультиприсваивания" — поэтому слева у вас по прежнему тупл, только анонимный. Все (ну или почти все) языки программирования с туплами, имеют синтаксический сахар, который позволяет пользоваться такой записью, но компилятор переписывает x,y,z как v$001._1 v$001._2 v$001._3. На самом деле это вырожденный случай паттерн-матчинга и вот такое например:
Честно говоря я слабо понимаю что ты тут написал. Скажем есть две такие вот строки:
local x,y,z = (1,2,3)
x = y + z
я не понимаю куда значение y + z запишется и причем там pattern matching вообще.
Z>
Z>local x,y,z = (1,2)
Z>
Z>... должно быть ошибкой даже в динамическом языке.
Наверное да.
Z>В идеале любая _запятая_ — конструктор тупла, поэтому аргументы мультиарных функций тоже туплы (ну а void это Unita любое значение это унарный тупл).
Скажем в одной функции (передатчик) у тебя есть
return (x,y,z);
Тогда на стороне приёмника ты получаешь tuple t к элементам которого ты можешь обращаться только как t[0], t[1], t[2] —
теряется семантика (имена) — т.е. maintenance этого кода будет ниже плинтуса.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, z00n, Вы писали:
Z>>Здравствуйте, c-smile, Вы писали:
CS>>>Самый распостраненный способ бороться с фрагментацией это GC насколько мне известно.
Z>>Способ с GC не годится, например, для игровых приставок.
CS>С этим можно поспорить. Например прототип моего TIScript — язык Bob (David Betz) — был сделан для DVD players (Toshiba, Samsung). CS>И он использует Cheney's moving GC. Работает эффективно. GC цикл — миллисекунды занимает. Для типовых задач UI automation памяти много не надо.
Ну, lua же не язык для разметки UI — на ней большие программы пишут, типа Asobе Lightroom
Z>>Или, например, когда команда Firefox боролась с фрагментацией — они меняли аллокатор на jemalloc: Z>>http://blog.pavlov.net/2007/11/10/memory-fragmentation/ Z>>http://blog.pavlov.net/2008/03/11/firefox-3-memory-usage/ Z>>http://blog.pavlov.net/2008/02/05/jemalloc-now-on-the-trunk/
CS>Честно говоря выбранный способ работы с памятью в JS в FireFox далек от оптимального решения. Выделять scripting objects в C heap это себя не любить. Насколько я знаю все остальные JS движки используют moving GCs в той или иной форме. Это кстати хорошо видно в Process Explorer — график выделения памяти. Почему-то мне казалось что Lua в этом смысле грамотнее сделан.
Там же речь идет не только о Javascript:
As you might imagine, given the size of our codebase, we do allocations from lots and lots of different places. Fortunately, there are several hot spots. Those include Javascript, strings, sqlite, CSS parsing, HTML parsing, and array growing. For some of these we don’t need to heap allocate and can just do temporary allocations on the stack. For others we can’t, but we can use arenas (as we already do for some layout objects) to help reduce fragmentation.
Но я попросил практический пример, как авторы большой программы на С/С++ заменили аллокатор на копирующий GC в целях борьбы с фрагментацией.
Мне как раз разоны авторов луа понятны — они починили слабое место — в целях борьбы с пузами сделали Incremental GC, но не стали диктовать пользователям как им выделять память в их Xbox360. Я не против fancy GC — я не считаю это критическим недостатком lua.
CS>Дело в том что tuple это объект который аллоцируется в heap. В случае Lua который использует достаточно дорогой аллокатор (C CS> malloc) генерация таких tuples будет весьма грустной. CS>Вот это вот в Lua (и в tiscript): CS>
CS>local x,y,z = 1,2,3
CS>
CS>разворачивается в последоваетльность PUSH/POP/STORE(VAR) байткод-команд, т.е. на стеке — память вообще не аллоцируется.
Это все детали реализации — все сопутствущие проблемы производительности решены Computer Science десятилетия назад.
CS> ... Честно говоря я слабо понимаю что ты тут написал. Скажем есть две такие вот строки:
CS>
CS>local x,y,z = (1,2,3)
CS>x = y + z
CS>
CS> я не понимаю куда значение y + z запишется и причем там pattern matching вообще.
Так понятнее?
-- компилятор переписывает это как:
local v$001 = (1,2,3)
local x = v$001._1
local y = v$001._2
local z = v$001._3
CS>я не понимаю куда значение y + z запишется и причем там pattern matching вообще.
Паттерн матчинг там притом, что 1,2,3 могут быть туплами тоже (они же у нас первоклассные сущности). В простом случае, когда вложенные туплы запрещены (это глупо, имхо) — паттерн матчинг вырождается в то, что я выше написал
Z>>В идеале любая _запятая_ — конструктор тупла, поэтому аргументы мультиарных функций тоже туплы (ну а void это Unita любое значение это унарный тупл).
CS>Скажем в одной функции (передатчик) у тебя есть
CS>
CS>return (x,y,z);
CS>
CS>Тогда на стороне приёмника ты получаешь tuple t к элементам которого ты можешь обращаться только как t[0], t[1], t[2] — CS>теряется семантика (имена) — т.е. maintenance этого кода будет ниже плинтуса.
CS>Тогда как это: CS>
CS>local x,y,z = get_3D_coordinate()
CS>
CS>более гуманно, нет?
При наличии паттерн-матчинга туплы гуманнее некуда (код на Scala для примера). Без паттерн матчинга — да, не фонтан, это продемонстрировал C# 4.0.
$ scala
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_13).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val outer@(x,y) = (1,(2, 3))
outer: (Int, (Int, Int)) = (1,(2,3))
x: Int = 1
y: (Int, Int) = (2,3)
scala> outer
res0: (Int, (Int, Int)) = (1,(2,3))
scala> x
res1: Int = 1
scala> y
res2: (Int, Int) = (2,3)
scala>
Здравствуйте, z00n, Вы писали:
Z>>>Способ с GC не годится, например, для игровых приставок.
CS>>С этим можно поспорить. Например прототип моего TIScript — язык Bob (David Betz) — был сделан для DVD players (Toshiba, Samsung). CS>>И он использует Cheney's moving GC. Работает эффективно. GC цикл — миллисекунды занимает. Для типовых задач UI automation памяти много не надо.
Z>Ну, lua же не язык для разметки UI ...
"язык для разметки UI" это html.
Z>... на ней большие программы пишут, типа Adobе Lightroom
Эдаким макаром можно говорить что один самый крутой антивирус написан на моем tiscript. Но понятно что это не так.
Скриптовые языки по определению это клей — вызвать одну native function и передать результат на вход другой. По большому счету.
Это я к тому что "большие программы писать"... короче, надо конкретно понимать на каком языке это можно делать а на каком нет.
Z>>>Или, например, когда команда Firefox боролась с фрагментацией — они меняли аллокатор на jemalloc: Z>>>http://blog.pavlov.net/2007/11/10/memory-fragmentation/ Z>>>http://blog.pavlov.net/2008/03/11/firefox-3-memory-usage/ Z>>>http://blog.pavlov.net/2008/02/05/jemalloc-now-on-the-trunk/
CS>>Честно говоря выбранный способ работы с памятью в JS в FireFox далек от оптимального решения. Выделять scripting objects в C heap это себя не любить. Насколько я знаю все остальные JS движки используют moving GCs в той или иной форме. Это кстати хорошо видно в Process Explorer — график выделения памяти. Почему-то мне казалось что Lua в этом смысле грамотнее сделан.
Z>Там же речь идет не только о Javascript:
Z>
Z>As you might imagine, given the size of our codebase, we do allocations from lots and lots of different places. Fortunately, there are several hot spots. Those include Javascript, strings, sqlite, CSS parsing, HTML parsing, and array growing. For some of these we don’t need to heap allocate and can just do temporary allocations on the stack. For others we can’t, but we can use arenas (as we already do for some layout objects) to help reduce fragmentation.
О как ... Смешались в кучу кони, люди ...
Для HTML parsing например память вообще выделять не надо. Вот тебе пример парсера который ничего не выделяет, в смысле вообще ничего: http://www.codeproject.com/KB/recipes/HTML_XML_Scanner.aspx .
Не имею понятия что там такого мозиллоиды умудрились навыделять. FF вообще знаменит своим расходом памяти.
А у JavaScript совершенно независимый pattern работы с памятью.
По спецификации JavaScript есть GC-able среда. И типичный код (скажем jQuery) это очень частое создание мелких объектов и массивов.
Скорость выделения памяти в GC это скорость инкремента указателя и одного if( free < top ) ...
Поэтому лучшие собаководы используют moving GC. Скажем V8 использует moving GC на young generation. Также как и на old generation впрочем.
Вот можно посмотреть http://www.youtube.com/watch?v=FrufJFBSoQY , если лень всё смотреть то где-то на 45 минуте там разговор про scalability c графиками.
Z>>>Буду признателен за примеры борьбы посредством GC (за исключением очевидных: "перешли на Java/C#/Erlang" ).
Z>Но я попросил практический пример, как авторы большой программы на С/С++ заменили аллокатор на копирующий GC в целях борьбы с фрагментацией.
Я не понял причем здесь "программы на С/С++". Мы же про Lua и JS говорим как бы. В этих языках нет delete в смысле C++. Также как и нет возможности выделять память скажем объектов или массивов на стеке.
Про практический пример...
Да всё та же Mozilla кстати. У знаю людей которые делали mobile port FF. Больше не делают потому как "воно не лизе".
Наивная работа с памятью — и никому ты на mobile не нужон. Что-то мне говорит что FF вообще скоро переползет на WebKit и V8.
Z>Мне как раз разоны авторов луа понятны — они починили слабое место — в целях борьбы с пузами сделали Incremental GC, но не стали диктовать пользователям как им выделять память в их Xbox360. Я не против fancy GC — я не считаю это критическим недостатком lua.
Честно говоря Lua/Python способ работы с памятью это именно и есть "fancy GC", чаще это называется naïve GC.
Java, .NET, Lisp и его производные, м пр. все используют нормальный GC
CS>>Дело в том что tuple это объект который аллоцируется в heap. В случае Lua который использует достаточно дорогой аллокатор (C CS> malloc) генерация таких tuples будет весьма грустной. CS>>Вот это вот в Lua (и в tiscript): CS>>
CS>>local x,y,z = 1,2,3
CS>>
CS>>разворачивается в последоваетльность PUSH/POP/STORE(VAR) байткод-команд, т.е. на стеке — память вообще не аллоцируется.
Z>Это все детали реализации — все сопутствущие проблемы производительности решены Computer Science десятилетия назад.
Ну наверное.
CS>> ... Честно говоря я слабо понимаю что ты тут написал. Скажем есть две такие вот строки:
CS>>
CS>>local x,y,z = (1,2,3)
CS>>x = y + z
CS>>
CS>> я не понимаю куда значение y + z запишется и причем там pattern matching вообще.
Z>Так понятнее?
Z>
Z> -- компилятор переписывает это как:
Z>local v$001 = (1,2,3)
Z>local x = v$001._1
Z>local y = v$001._2
Z>local z = v$001._3
Z>
И чего конкретно тебе это дает?
У меня компайлер в этом случае генерирует просто:
local x = 1
local y = 2
local z = 3
и никакой памяти для этой операции не требуется, стек/регистры толко участвуют.
Ну т.е. если ты строишь нечто типа сферического файрфокса в памяти то да, можно и протуплить это все дело.
CS>>я не понимаю куда значение y + z запишется и причем там pattern matching вообще.
Z>Паттерн матчинг там притом, что 1,2,3 могут быть туплами тоже (они же у нас первоклассные сущности). В простом случае, когда вложенные туплы запрещены (это глупо, имхо) — паттерн матчинг вырождается в то, что я выше написал
Ну вот, сразу всё стало понятно.
А причем там pattern matching вообще, кстати?
Z>>>В идеале любая _запятая_ — конструктор тупла, поэтому аргументы мультиарных функций тоже туплы (ну а void это Unita любое значение это унарный тупл).
void это есть 0-tuple тогда уже. А вектор аргументов и есть tuple в самом своем сермяжном виде. multi-returns это симметричная конструкция вектору аргументов.
Не вижу смысла в каких-то абстракциях еще там.
Z>
Z>$ scala
Z>Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_13).
Z>Type in expressions to have them evaluated.
Z>Type :help for more information.
scala>> val outer@(x,y) = (1,(2, 3))
Z>outer: (Int, (Int, Int)) = (1,(2,3))
Z>x: Int = 1
Z>y: (Int, Int) = (2,3)
scala>> outer
Z>res0: (Int, (Int, Int)) = (1,(2,3))
scala>> x
Z>res1: Int = 1
scala>> y
Z>res2: (Int, Int) = (2,3)
scala>>
Z>
Круто. А зачем это всё? Для практики я имею ввиду...
Z>>... на ней большие программы пишут, типа Adobе Lightroom
CS>Эдаким макаром можно говорить что один самый крутой антивирус написан на моем tiscript. Но понятно что это не так.
Тут кстати всплывает второй большой недостаток луа (я не помню упоминал или нет) — луа из коробки не умеет их (lua_threads) сериализовать — для этого есть внешняя библиотека Pluto, которая повторяет изрядные куски lua-codebase. Я считаю, что разработчикам стоит встроить внутрь прозрачную сериализацию состояния VM .
Z>>Но я попросил практический пример, как авторы большой программы на С/С++ заменили аллокатор на копирующий GC в целях борьбы с фрагментацией.
CS>Я не понял причем здесь "программы на С/С++". Мы же про Lua и JS говорим как бы. В этих языках нет delete в смысле C++. Также как и нет возможности выделять память скажем объектов или массивов на стеке.
Луа практически не применяется как самостоятельный язык (в отличие от питона, например) — поэтому какой бы GC вы в нее не встроили это никак не решит проблем фрагментации на стороне С. А их все равно приходится решать — игроделы обычно пишут custom-аллокаторы, в том числе и для луа.
Z>>Мне как раз разоны авторов луа понятны — они починили слабое место — в целях борьбы с пузами сделали Incremental GC, но не стали диктовать пользователям как им выделять память в их Xbox360. Я не против fancy GC — я не считаю это критическим недостатком lua.
CS>Java, .NET, Lisp и его производные, м пр. все используют нормальный GC
Это все "самостоятельные" языки, ими редко расширяют С.
CS>У меня компайлер в этом случае генерирует просто: CS>
CS>local x = 1
CS>local y = 2
CS>local z = 3
CS>
CS>и никакой памяти для этой операции не требуется, стек/регистры толко участвуют.
CS>Ну т.е. если ты строишь нечто типа сферического файрфокса в памяти то да, можно и протуплить это все дело.
Я напомню — туплы нужны потому, что эмулировать их, когда их нужно много, с помощью массива/хеша дорого. А вот если они есть, то стоит заменить мультиприсваивание на нормальные операции с туплами и это можно сделать без накладных расходов. Если вы не понимаете преимуществ того, что в языке все должно быть первоклассно и ортогонально — я не готов тратить время на то, чтобы вас переубедить
Z>>>>В идеале любая _запятая_ — конструктор тупла, поэтому аргументы мультиарных функций тоже туплы (ну а void это Unita любое значение это унарный тупл).
CS>void это есть 0-tuple тогда уже. А вектор аргументов и есть tuple в самом своем сермяжном виде. multi-returns это симметричная конструкция вектору аргументов. CS>Не вижу смысла в каких-то абстракциях еще там.
По идее void конечно Unit (так принято называть 0-tuple в кругах CS), но в С-подобных языках void не первоклассный и поэтому в C# уже появился настоящий System.Unit
Вектор аргументов, если он первоклассный, вполне себе тупл (в JS это возможно и так) — но в Lua 'stack' аргументов не первоклассный и вот так сделать нельзя:
function a(x, y, ...)
local z = x+y
return b(z, ...) -- <- фигу
end
нужно сериализовть аргументы в array и распаковывать их при вызове следующей функции:
function a(x, y, ...)
local z = x+y
local args = {...} -- <- pack stack to array
return b(z, unpack(args)) -- <- unpack array to stack
end
Любого функционального программиста это бесит неимоверно!
Z>... (some scala code)
CS> Круто. А зачем это всё? Для практики я имею ввиду...
В статически типизированном языке это одна из самых практических вещей на свете — посмотрите на страдания C# ввести сначала анонимные типы а теперь туплы. Только без паттерн-матчинга не выходит ни хрена. Тут на форуме есть несколько сотен постов на эту тему — если интересно — почитайте.
Z>Вектор аргументов, если он первоклассный, вполне себе тупл (в JS это возможно и так) — но в Lua 'stack' аргументов не первоклассный и вот так сделать нельзя: Z>
Z>function a(x, y, ...)
Z> local z = x+y
Z> return b(z, ...) -- <- фигу
Z>end
Z>
Z>нужно сериализовть аргументы в array и распаковывать их при вызове следующей функции:
Z>
Z>function a(x, y, ...)
Z> local z = x+y
Z> local args = {...} -- <- pack stack to array
Z> return b(z, unpack(args)) -- <- unpack array to stack
Z>end
Z>
Z>Любого функционального программиста это бесит неимоверно!
Еще раз повторю свой тезис: для того чтобы tuples работали в Lua в нём/ней должен быть соотв. moving менеджер памяти. Как минимум такой же как в Lisp.
Паттерн использования tuples это массовая аллокация/освобождение мелких объектов переменной длины. Non-moving heaps (например C/C++) по определению крайне не эффективны для этого — фрагментация памяти и дорогая процедура выделения/освобождения. Я думаю что это очевидно.
CS>> Круто. А зачем это всё? Для практики я имею ввиду... Z>В статически типизированном языке это одна из самых практических вещей на свете — посмотрите на страдания C# ввести сначала анонимные типы а теперь туплы. Только без паттерн-матчинга не выходит ни хрена.
Так, опять мы куда-то не туда уехали...
Мы говорим про Lua/JS или про "статически типизированные языки"?
Z>Тут на форуме есть несколько сотен постов на эту тему — если интересно — почитайте.
"Тут" это где? В "языки с динамической типизацией"?
И вот кстати "паттерн-матчинга не выходит ни хрена". Что конкретно не выходит?
И какие конкретно есть задачи для которых паттерн-матчинг это "самое оно"? Если не затруднит конечно.
Здравствуйте, c-smile, Вы писали:
CS>Еще раз повторю свой тезис: для того чтобы tuples работали в Lua в нём/ней должен быть соотв. moving менеджер памяти. Как минимум такой же как в Lisp.
CS>Паттерн использования tuples это массовая аллокация/освобождение мелких объектов переменной длины. Non-moving heaps (например C/C++) по определению крайне не эффективны для этого — фрагментация памяти и дорогая процедура выделения/освобождения. Я думаю что это очевидно.
А вам в третий раз повторю, что мне неинтересно обсуждать реализацию тривиальных вещей. И кстати — нет такого языка — Lisp c большой буквы — есть десяток реализаций CL, есть 2-3 десятка реализаций Scheme, есть Clojure и.т.д. Все они используют дастаточно разные стратегии работы с памятью, вплоть до использования обычного Boeghm GC.
В качестве языка название которого совпадает с реализацией приводите OCAML, Erlang или ATS — не ошибетесь
CS>>> Круто. А зачем это всё? Для практики я имею ввиду... Z>>В статически типизированном языке это одна из самых практических вещей на свете — посмотрите на страдания C# ввести сначала анонимные типы а теперь туплы. Только без паттерн-матчинга не выходит ни хрена.
CS>Так, опять мы куда-то не туда уехали... CS>Мы говорим про Lua/JS или про "статически типизированные языки"?
Невозможно привести привести практические примеры применения PM оставаясь в рамках Lua/JS по причине отсутствия в них PM.
Динамические языки в целом — тоже не фонтан, поскольку PM там поддерживает только Erlang и Oz.
Вам же, я думаю, все равно — Scala или Erlang?
CS>И вот кстати "без паттерн-матчинга не выходит ни хрена". Что конкретно не выходит?
Убрать уродство:
Tuple<string,int> tp = Foo();
string x = tp.Item1;
int y = tp.Item2;
CS>И какие конкретно есть задачи для которых паттерн-матчинг это "самое оно"? Если не затруднит конечно.
Любые, в решении которых есть 'if', 'switch' etc.
-- проверка валидности
-- без PM
local result = null
local x,y = someFunction(somearg)
if (x != "tag001")
throw "error"
else
result = nextFun(y)
-- c PM
local "tag001", y = someFunction(somearg)
local result = nextFun(y)
Чем сложнее структура — тем больше выыигрыш от PM. Это, переписаное на if-ах займет больше сотни строк и будет нечитабельно:
-- fits :: (int,int,Cells) -> boolean
-- @w - ribbon space left
-- @k - current column
-- Cells :: [{indent,Mode,Doc}]
local function fits
| w,_,_ if w < 0 -> false
| _,_,[] -> true
| w,k,{i,m,Empty} :: z -> fits(w,k,z)
| w,k,{i,m,`Cat{x,y}} :: z -> fits(w,k,{i,m,x}::{i,m,y}::z)
| w,k,{i,m,`Nest{j,x}} :: z -> fits(w,k,{i+j,m,x}::z)
| w,k,{i,m,`Text{s}} :: z -> fits(w-#s,k+#s,z)
| w,k,{i,FL,`Break{s}} :: z -> fits(w-#s,k+#s,z)
| w,k,{i,BR,`Break{_}} :: z -> true
| w,k,{i,m,`Group{x}} :: z -> fits(w,k,{i,m,x}::z)
| w,k,{i,m,`Column{f}} :: z -> fits(w,k,{i,m,f(k)}::z)
| w,k,{i,m,`Nesting{f}} :: z -> fits(w,k,{i,m,f(i)}::z)
| _,_,x -> error(tostring(x))
end
Здравствуйте, c-smile, Вы писали:
CS>Нормальный GC предполагает компактификацию памяти, т.е. например объекты могут перемещаться в heap в результате GC.
А всегда ли борьба с фрагментацией оправдывает двойной расход памяти?
Здравствуйте, Трурль, Вы писали:
CS>>Нормальный GC предполагает компактификацию памяти, т.е. например объекты могут перемещаться в heap в результате GC.
Т>А всегда ли борьба с фрагментацией оправдывает двойной расход памяти?
Двойной вовсе не обязателен. См. GC в CLR, например. Или вопрос про чью-то конкретную реализацию?
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, Трурль, Вы писали:
CS>>>Нормальный GC предполагает компактификацию памяти, т.е. например объекты могут перемещаться в heap в результате GC.
Т>>А всегда ли борьба с фрагментацией оправдывает двойной расход памяти?
DM>Двойной вовсе не обязателен. См. GC в CLR, например. Или вопрос про чью-то конкретную реализацию?
Двойной это еще хорошо. На практике это отношение даже еще больше.
[GC 325407K->83000K(776768K), 0.2300771 secs]
GC — Indicates that it was a minor collection (young generation). If it had said Full GC then that indicates that it was a major collection (tenured generation).
325407K — The combined size of live objects before garbage collection.
83000K — The combined size of live objects after garbage collection.
(776768K) — the total available space, not counting the space in the permanent generation, which is the total heap minus one of the survivor spaces.
0.2300771 secs — time it took for garbage collection to occur.
Здесь 83000K — это выжившие объекты — т.е. это реальная память которая нужна для представления объектов системы.
а 325407K — это выжившие объекты + мусор.
Т.е. для работы такой системы нужно в 325407K/83000K = 3.9 раз больше чем нужно для используемых объектов.
И кстати оношение 776768K (полная память отобранная у системы) / 325407K (переполнение когда произошел GC) = 2.3 показывает
что в Java как минимум для young generation используется нечто типа copying GC (т.е. память разбита на две половины).
В C heap есть тоже overhead — 70%-90% процентов отобранной памяти используется реально.
Но в C heap операция выделения памяти достаточно CPU-ёмкая. Чем эффективнее память используется тем больше CPU нужно на аллокацию.
В managed heaps CPU экономится за счет выделения памяти в 5-10 раз больше чем нужно для представления объектов.
Чудес как всегда не бывает — или память кушаем или CPU потребляем.