Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, gandjustas, Вы писали:
_>>>Непонятно в чём проблема. Вот имеем мы чистую функцию. Что это значит с точки зрения оптимизатора? Что результат её вызова с одними аргументами можно кэшировать и что можно произвольно передвигать точку её вызова (это кстати включает в себя ленивость). И чем может помешать оптимизатору нахождение рядом с вызовом чистой функции вызова ещё и не чистой? Да, со второй функции он не сможет ничего этого делать. Ну так мы и не требуем этого.
G>>Так и с первой не может ничего делать, если обе функции обращаются к одним и тем же данным. G>>А как гарантировать что нечистые функции не влияют на чистые?
DM>В D чистая функция "does not read or write any global or static mutable state" помимо прочего. Так что помешать ей не получится, если конечно не идти намеренно против системы типов, но тогда уже вся ответственность на нарушителе.
Это хорошо. А если данные не global и не static? Например есть объект у которого есть не изменяющий состояние метод и метод с сайд-эффектами, компилятор скажет что-нибудь по этому поводу?
Re[76]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так а он и не должен компилироваться в таком случае — нам же необходимо гарантировать компилятором равенство длин векторов. А если бы такое собиралось, то добавление банального n++ в середину сразу же давало бы неправильную программу.
Ну я как бы не против, чтобы программа с добавлением n++ в середину ломалась. Просто здесь мы видим ограниченность компилятора: он в упор не видит того, что никакого n++ тут нету. Точнее, ограниченность решения. Ведь даже если я подставлю в обе строчки вместо n 42, компилятор по-прежнему не даст скомпилировать программу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
DM>>В D чистая функция "does not read or write any global or static mutable state" помимо прочего. Так что помешать ей не получится, если конечно не идти намеренно против системы типов, но тогда уже вся ответственность на нарушителе.
G>Это хорошо. А если данные не global и не static?
Тут хуже. Если передается мутабельный объект, то "в одну реку нельзя войти дважды", никакого кэширования не будет. Но, как ни странно, компилятор не будет возражать называть функцию чистой.
G> Например есть объект у которого есть не изменяющий состояние метод и метод с сайд-эффектами, компилятор скажет что-нибудь по этому поводу?
Да, много всякого может сказать. Там есть три варианта: мутабельный, const и immutable. Когда метод помечен одним из способов, это воспринимается как если бы весь объект при вызове данного метода был такой, а потому мешать их сложно. Если создать объект как иммутабельный, там меняющие состояния методы не будут доступны, например. И наоборот, если не путаю.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Так и с первой не может ничего делать, если обе функции обращаются к одним и тем же данным.
Что значит обращается? Если в смысле передачи параметра, то как бы нет никаких проблем. А если имеется в виду обращение изнутри функции к каким-то другим внешним неконстантным данным, то очевидно, что такая функция не является чистой.
G>Если неконстантный объект имеет общие данные с константным, то результат программы может оказаться разным при копировании и передаче ссылки. Кстати константность вообще не гарантия, поэтому компилятор не производит никаких оптимизаций на основе константности.
Это в каком языке интересно? )
G>А как гарантировать что нечистые функции не влияют на чистые?
Это должен делать компилятор (он просто не скомпилирует код, в котором модификатором pure помечены неправильные функции). В языке D такое есть. И в принципе возможно ввести подобное во многие языки.
Re[77]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Ну я как бы не против, чтобы программа с добавлением n++ в середину ломалась. Просто здесь мы видим ограниченность компилятора: он в упор не видит того, что никакого n++ тут нету. Точнее, ограниченность решения. Ведь даже если я подставлю в обе строчки вместо n 42, компилятор по-прежнему не даст скомпилировать программу.
Так это уже просто совсем другая задача. Если мы хотим проверять равенство не по построению, а по реальному значению, то тогда всё намного проще. Если оно известно на момент компиляции (как 42 например), то решением будет уже готовый библиотечный класс std::array. А если не известно, то соответственно будет уже просто обычный if в рантайме. Изначально же мы решали задачу сравнения по построению, а не по значению и вот как раз она уже не такая стандартная...
Re[78]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Sinclair, Вы писали:
S>>Ну я как бы не против, чтобы программа с добавлением n++ в середину ломалась. Просто здесь мы видим ограниченность компилятора: он в упор не видит того, что никакого n++ тут нету. Точнее, ограниченность решения. Ведь даже если я подставлю в обе строчки вместо n 42, компилятор по-прежнему не даст скомпилировать программу.
_>Так это уже просто совсем другая задача. Если мы хотим проверять равенство не по построению, а по реальному значению, то тогда всё намного проще. Если оно известно на момент компиляции (как 42 например), то решением будет уже готовый библиотечный класс std::array. А если не известно, то соответственно будет уже просто обычный if в рантайме. Изначально же мы решали задачу сравнения по построению, а не по значению и вот как раз она уже не такая стандартная...
Задача, на сколько понимаю, ставиться так: выразить с помощью типизации, что ScalarProduct принимает коллекции одинаковой длины.
Чтобы, если компилятор мог себе доказать, что оба параметра одинаковой длины (например, по построению), компиляция проходила успешно, иначе — выдавалась ошибка компиляции и нужно было, например, добавлять условие:
//Длина коллекций, конечно, не обязана быть константой времени компиляции.
cin >> n;
cin >> m;
auto v1 = make(n);
auto v2 = make(m);
if(n==m)//условие
ScalarProduct(v1, v2);
, чтобы ублажить компилятор.
Re[79]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, artelk, Вы писали:
A>Задача, на сколько понимаю, ставиться так: выразить с помощью типизации, что ScalarProduct принимает коллекции одинаковой длины. A>Чтобы, если компилятор мог себе доказать, что оба параметра одинаковой длины (например, по построению), компиляция проходила успешно, иначе — выдавалась ошибка компиляции и нужно было, например, добавлять условие: A>
A>//Длина коллекций, конечно, не обязана быть константой времени компиляции.
A>cin >> n;
A>cin >> m;
A>auto v1 = make(n);
A>auto v2 = make(m);
A>if(n==m)//условие
A> ScalarProduct(v1, v2);
A>
A>, чтобы ублажить компилятор.
Задачка точно сформулирована здесь http://www.linux.org.ru/forum/development/4300872 и имеет два ключевых требования:
— проверка равенства размеров векторов на этапе компиляции
— размеры векторов не известны на момент компиляции.
Соответственно, сочетание этих требование и позволяет решать задачу исключительно методом сравнения размера по построению. Что является достаточно нестандартной задачкой. Хотя, как видно выше, на C++ она решается весьма просто. Кстати, можно было сделать и более красивое решение с помощью какого-нибудь там boost.proto, позволяющее реально произвольно задавать (и проверять) вектора, но это уже лень.
Ну а если убирать одно из этих требований, то просто получаем две тривиальнейших задачки с общеизвестными решениями через сравнение реальных размеров.
Re[80]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Задачка точно сформулирована здесь http://www.linux.org.ru/forum/development/4300872 и имеет два ключевых требования: _> — проверка равенства размеров векторов на этапе компиляции _> — размеры векторов не известны на момент компиляции.
Там написано "Нам хочется, чтобы компилятор гарантировал нам, что длины этих векторов одинаковы". Это не эквивалентно "проверке равенства размеров векторов на этапе компиляции".
Предложенный вариант с if вполне корректен (при условии, что компилятор будет требовать его наличие).
Re[81]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Там написано "Нам хочется, чтобы компилятор гарантировал нам, что длины этих векторов одинаковы". Это не эквивалентно "проверке равенства размеров векторов на этапе компиляции". ARK>Предложенный вариант с if вполне корректен (при условии, что компилятор будет требовать его наличие).
Ну там же есть примеры решения на Java/C# (заметно менее удобные, чем на C++), которые однозначно демонстрируют, что конкретно подразумевал автор задачки. Вот http://www.linux.org.ru/forum/development/4300872/page3#comment-4305706 например. И там в каждом варианте есть закомментированная строка, наличие которой блокирует компиляцию.
Re[82]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну там же есть примеры решения на Java/C# (заметно менее удобные, чем на C++), которые однозначно демонстрируют, что конкретно подразумевал автор задачки. Вот http://www.linux.org.ru/forum/development/4300872/page3#comment-4305706 например. И там в каждом варианте есть закомментированная строка, наличие которой блокирует компиляцию.
Да, верно. Не обратил внимания.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, gandjustas, Вы писали:
DM>>>В D чистая функция "does not read or write any global or static mutable state" помимо прочего. Так что помешать ей не получится, если конечно не идти намеренно против системы типов, но тогда уже вся ответственность на нарушителе.
G>>Это хорошо. А если данные не global и не static?
DM>Тут хуже. Если передается мутабельный объект, то "в одну реку нельзя войти дважды", никакого кэширования не будет. Но, как ни странно, компилятор не будет возражать называть функцию чистой.
G>> Например есть объект у которого есть не изменяющий состояние метод и метод с сайд-эффектами, компилятор скажет что-нибудь по этому поводу?
DM>Да, много всякого может сказать. Там есть три варианта: мутабельный, const и immutable. Когда метод помечен одним из способов, это воспринимается как если бы весь объект при вызове данного метода был такой, а потому мешать их сложно. Если создать объект как иммутабельный, там меняющие состояния методы не будут доступны, например. И наоборот, если не путаю.
Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так? Ведь никак не проверяется что объект single-owned?
Кстати чем immutable отличается от const?
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Так и с первой не может ничего делать, если обе функции обращаются к одним и тем же данным.
_>Что значит обращается? Если в смысле передачи параметра, то как бы нет никаких проблем. А если имеется в виду обращение изнутри функции к каким-то другим внешним неконстантным данным, то очевидно, что такая функция не является чистой.
Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? интересует с точки зрения компилятора и потенциальных оптимизаций.
G>>Если неконстантный объект имеет общие данные с константным, то результат программы может оказаться разным при копировании и передаче ссылки. Кстати константность вообще не гарантия, поэтому компилятор не производит никаких оптимизаций на основе константности.
_>Это в каком языке интересно? )
Это в принципе в любом языке.
G>>А как гарантировать что нечистые функции не влияют на чистые?
_>Это должен делать компилятор (он просто не скомпилирует код, в котором модификатором pure помечены неправильные функции). В языке D такое есть.
Не силен в D, покажи пример.
_>И в принципе возможно ввести подобное во многие языки.
В общем случае получение такой гарантии приводит к решению проблемы останова. Так что в принципе ввести подобное в языки нельзя.
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так? Ведь никак не проверяется что объект single-owned?
http://nwcpp.org/talks/2009/accu.pdf
Насколько я помню, в D нет single-owned объектов (то бишь уникальных ссылок).
G>Кстати чем immutable отличается от const?
Immutable не меняется никем и никогда, const не меняется только текущим клиентом.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой?
Не будет. Чистые функции в D не могут никак взаимодействовать с изменяемым состоянием (даже читать его): http://dlang.org/function.html
a pure function:
•does not read or write any global or static mutable state
•cannot call functions that are not pure
•can override an impure function, but an impure function cannot override a pure one
•is covariant with an impure function
•cannot perform I/O
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
G>>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? ARK>Не будет. Чистые функции в D не могут никак взаимодействовать с изменяемым состоянием
К сожалению, еще как могут:
int gx = 5;
class A { int x, y; }
auto f(A a) pure
{
a.x = 1; // попытка обратиться к gx тут вызовет ожидаемую ошибку, а так все работаетreturn a.y + 2;
}
Ограничение лишь на глобальное состояние.
Правда, в доке упоминается еще "full, functional purity", когда она ничего не меняет, и тогда оптимизации сильнее, но на уровне языка это никак не отражено.
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
DM>>Да, много всякого может сказать. Там есть три варианта: мутабельный, const и immutable. Когда метод помечен одним из способов, это воспринимается как если бы весь объект при вызове данного метода был такой, а потому мешать их сложно. Если создать объект как иммутабельный, там меняющие состояния методы не будут доступны, например. И наоборот, если не путаю.
G>Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так?
Система типов мешает. Если он в одном потоке immutable, он и в любом другом будет immutable, если не идти на сознательное нарушение и использовать касты.
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>К сожалению, еще как могут: DM>Ограничение лишь на глобальное состояние.
Хм, если так, то это очень плохо.
По-хорошему, для таких фокусов параметры должны передаваться по значению или быть иммутабельными. Тут у Брайта какой-то адский косяк.
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, gandjustas, Вы писали:
DM>>>Да, много всякого может сказать. Там есть три варианта: мутабельный, const и immutable. Когда метод помечен одним из способов, это воспринимается как если бы весь объект при вызове данного метода был такой, а потому мешать их сложно. Если создать объект как иммутабельный, там меняющие состояния методы не будут доступны, например. И наоборот, если не путаю.
G>>Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так?
DM>Система типов мешает. Если он в одном потоке immutable, он и в любом другом будет immutable, если не идти на сознательное нарушение и использовать касты.
А в какой момент объект становится immutable? Как const в C++? Или на уровне типа задается? Или есть что-то типа механизма "заморозки" ?
Если ссылку на объект можно скопировать до того как он стал immutable, то гарантий по сути никаких нет.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, gandjustas, Вы писали:
G>>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой?
ARK>Не будет. Чистые функции в D не могут никак взаимодействовать с изменяемым состоянием (даже читать его): http://dlang.org/function.html ARK>
ARK>a pure function:
ARK>•does not read or write any global or static mutable state
ARK>•cannot call functions that are not pure
ARK>•can override an impure function, but an impure function cannot override a pure one
ARK>•is covariant with an impure function
ARK>•cannot perform I/O
А где здесь про состояние объекта? Оно не является global or static mutable state.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? интересует с точки зрения компилятора и потенциальных оптимизаций.
Что значит будет чистой или нет? ) Это решает программист, с помощью модификатора pure. А компилятор соответственно или позволяет собрать такой код или нет.
Далее, если мы говорим про такой объект, то это собственно по сути ничем не отличается от двух глобальных функций, которым передают в качестве параметра одну и ту же структуру. Ключевое тут "в качестве параметра", так что без проблем можно считать такую функцию чистой.
Только вот если передавать этой нашей чистой функции неконстантную функцию (или в случае ООП, вызывая метод неконстантного объекта), то очевидно, что никакие оптимизации типа кэширования или перемещения точки вызова невозможны, т.к. это будут вызовы с потенциально разными аргументами.
G>Это в принципе в любом языке.
Ну ну) А ничего что например в C++ константные данные располагаются вообще в другой памяти? ) Это конечно же если компилятор вообще будет выделять память под них — в большинстве случаев оно может просто в ассемблерном коде оказаться зашиты. )))
G>Не силен в D, покажи пример.
В ответ на такой код
int data;
pure int f(){return data;}
компилятор скажет: "Error: pure nested function 'f' cannot access mutable data 'data'".
G>В общем случае получение такой гарантии приводит к решению проблемы останова. Так что в принципе ввести подобное в языки нельзя.