Предположим, что в энергичном языке при вызове foo(x, y, z) аргументы вычисляются не слева направо, а наоборот, т.е. сначала вычисляется z, потом y, потом x. При остальных вычислениях порядок стандартный.
Вопросы:
— Чем это может быть плохо/чревато, кроме того, что в случаях "невычисляемости" списка аргументов вылет будет происходить не "в том месте".
— Есть ли какие-нибудь языки с подобными извращениями? Как по реализации, так и — что интересней — по стандарту. Может, это типичный прикол?
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Предположим, что в энергичном языке при вызове foo(x, y, z) аргументы вычисляются не слева направо, а наоборот, т.е. сначала вычисляется z, потом y, потом x. При остальных вычислениях порядок стандартный.
ВВ>Вопросы: ВВ>- Чем это может быть плохо/чревато, кроме того, что в случаях "невычисляемости" списка аргументов вылет будет происходить не "в том месте". ВВ>- Есть ли какие-нибудь языки с подобными извращениями? Как по реализации, так и — что интересней — по стандарту. Может, это типичный прикол?
В сях аргументы заталкиваются в стек, начиная с последнего. Вычисляются они тоже чаще всего соответственно.
Здравствуйте, Socrat, Вы писали:
S>В сях аргументы заталкиваются в стек, начиная с последнего. Вычисляются они тоже чаще всего соответственно.
Интересно, а это особенность реализации или стандарт? Студии у меня под рукой нет, я так понимаю, что — положим, в VC — вызов функции вида foo(x, y), где оба аргумента являются невычисляемыми (приводят к ошибке), вылетит на вычислении именно у?
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Интересно, а это особенность реализации или стандарт?
Зачем так сделано — я не знаю. Единственное, что приходит на ум — функции с переменным количеством параметров, например, printf. Поскольку в них обработка идет с первого параметра, то логично, что он будет последним заталкиваться в стек.
ВВ>Студии у меня под рукой нет, я так понимаю, что — положим, в VC — вызов функции вида foo(x, y), где оба аргумента являются невычисляемыми (приводят к ошибке), вылетит на вычислении именно у?
Не знаю, вполне возможно, что порядок вычисления параметров может меняться. Особенно, если используется быстрый вызов функций, когда параметры кладутся в регистры.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Предположим, что в энергичном языке при вызове foo(x, y, z) аргументы вычисляются не слева направо, а наоборот, т.е. сначала вычисляется z, потом y, потом x. При остальных вычислениях порядок стандартный.
ВВ>Вопросы: ВВ>- Чем это может быть плохо/чревато, кроме того, что в случаях "невычисляемости" списка аргументов вылет будет происходить не "в том месте".
может быть чревато разным поведением побочных эффектов.
ВВ>- Есть ли какие-нибудь языки с подобными извращениями? Как по реализации, так и — что интересней — по стандарту. Может, это типичный прикол? http://msdn.microsoft.com/en-us/library/984x0h58%28VS.80%29.aspx
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, Socrat, Вы писали:
ВВ>Интересно, а это особенность реализации или стандарт?
Стандарт явно указывает, что порядок вычисления параметров может быть любым.
вызов функций справа налево нарушает укоренившуюся привычку программиста писать код слева направо.
допустим есть функции:
bool print(string text) // которая выводит текст, и возвращает ошибку через результат: true - ok, false - error
bool and(params bool[] vals) //обычный and от нескольких параметров
Это интересная проблема, побочные эффекты я, конечно, вообще упустил из вида
С другой стороны даже если __stdcall вычисляет параметры справа налево, то, видимо, указанное поведение не будет таким уж непривычным для программиста?
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, DarkGray, Вы писали:
ВВ>Это интересная проблема, побочные эффекты я, конечно, вообще упустил из вида ВВ>С другой стороны даже если __stdcall вычисляет параметры справа налево, то, видимо, указанное поведение не будет таким уж непривычным для программиста?
В С++ неважно слева направо или наоборот, т.к. в общем случае неопределен порядок вычисления подвыражений. Поэтому, например, в таком коде:
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>В С++ неважно слева направо или наоборот, т.к. в общем случае неопределен порядок вычисления подвыражений. Поэтому, например, в таком коде: ЮЖ>
Ну тут ссылку приводили на MS-specific. Хз, как там с этим. Если б помнил, не спрашивал.
По стандарту я так понял, нельзя вообще закладываться на то, что сайд эффекты будут происходить в определенном порядке — т.е. пример, приведенный DarkGray, с этой точки зрения просто адское зло.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Предположим, что в энергичном языке при вызове foo(x, y, z) аргументы вычисляются не слева направо, а наоборот, т.е. сначала вычисляется z, потом y, потом x. При остальных вычислениях порядок стандартный.
Стандарты подавляющего большинства языков не определяют этот порядок.
То, в каком порядке это происходит — это относится не к языку, а к так называемому calling convention. http://en.wikipedia.org/wiki/X86_calling_conventions
ВВ>Вопросы: ВВ>- Есть ли какие-нибудь языки с подобными извращениями?
Конечно. Например, так происходит при "pascal calling convention".
Ты можешь указать тип convention в своей программе на C++ при определении функции, так что язык тут не причем.
И это не самый странный convention. Вот, например, fastcall, при котором возможна ситуация, когда стек вообще не задействуется. Более того, компилятор имеет полное право воткнуть fastcall автоматически, если решит, что так лучше.
fastcall
Conventions entitled fastcall have not been standardized, and have been implemented differently, depending on the compiler vendor[1]. Typically fastcall calling conventions pass one or more arguments in registers which reduces the number of memory accesses required for the call. Microsoft fastcall
Microsoft or GCC [2] __fastcall[3] convention (aka __msfastcall) passes the first two arguments (evaluated left to right) that fit into ECX and EDX. Remaining arguments are pushed onto the stack from right to left. Borland fastcall
Evaluating arguments from left to right, it passes three arguments via EAX, EDX, ECX. Remaining arguments are pushed onto the stack, also left to right [4].
It is the default calling convention of Borland Delphi, where it is known as register.
Более современный — так сейчас происходит в 64-х битном Linux. Для функций с небольшим количеством аргументов ничего на стек не кладется, ни в каком порядке.
AMD64 ABI convention
The calling convention of the AMD64 application binary interface[8] is followed on Linux and other non-Microsoft operating systems. The registers RDI, RSI, RDX, RCX, R8 and R9 are used for integer and pointer arguments while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments. As in the Microsoft x64 calling convention, additional arguments are pushed onto the stack and the return value is stored in RAX.
Здравствуйте, Gaperton, Вы писали:
G>Стандарты подавляющего большинства языков не определяют этот порядок. G>То, в каком порядке это происходит — это относится не к языку, а к так называемому calling convention. G>http://en.wikipedia.org/wiki/X86_calling_conventions
Ну как бы я более широко рассматриваю этот вопрос. Для интерпретируемого языка, к примеру, это все пофиг, порядок исчисления может быть определен в стандарте.
ВВ>>Вопросы: ВВ>>- Есть ли какие-нибудь языки с подобными извращениями? G>Конечно. Например, так происходит при "pascal calling convention". G>Ты можешь указать тип convention в своей программе на C++ при определении функции, так что язык тут не причем.
Вопрос как-то все сводится к С++. Но как мне тут напомнили, С++ это плохой пример, т.к. собственно стандарт не гарантирует порядка сайд-эффектов, а в этом смысле программисту должно быть вообще пофиг, в каком там порядке вычисляются аргументы — хоть справа, хоть слева, хоть рандомно.
Вопрос можно поставить по-другому — есть ли энергичные языки, в которых порядок вычисления аргументов справа налево определен в стандарте — при том, что порядок вычисления остальных операций стандартный?
ВВ>С другой стороны даже если __stdcall вычисляет параметры справа налево, то, видимо, указанное поведение не будет таким уж непривычным для программиста?
вы здесь говорите про __stdcall, fastcall и т.д.
но порядок передачи аргументов в функцию не имеет никакого отношения к порядку вызова функций.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Вопрос можно поставить по-другому — есть ли энергичные языки, в которых порядок вычисления аргументов справа налево определен в стандарте — при том, что порядок вычисления остальных операций стандартный?
А. В такой постановке — черт его знает.
Но я лично сильно в этом сомневаюсь. Причины две.
1) Нижележащие API (в частности, ОС) и библиотеки (включая динамические) могут быть написаны на разных языках, отличных от целевого, и уже поэтому convention неразумно делать частью стандарта конкретного языка. Создаст лишние сложности.
2) Закладка в программе на порядок вычисления аргументов функции — сама по себе очень плохая практика. Это неочевидно, и хрен поймешь.
Поэтому, включать порядок вычисления аргументов в стандарт — никакой пользы кроме вреда. Не думаю, что удастся найти такой язык. Разве что поискать среди ранних, вроде Fortran-ов. Он крив как турецкая сабля. Но в те времена и стандартов-то на языки не было .
Здравствуйте, DarkGray, Вы писали:
ВВ>>С другой стороны даже если __stdcall вычисляет параметры справа налево, то, видимо, указанное поведение не будет таким уж непривычным для программиста?
DG>вы здесь говорите про __stdcall, fastcall и т.д. DG>но порядок передачи аргументов в функцию не имеет никакого отношения к порядку вызова функций.
На регистрово-ограниченных архитектурах имеет самое прямое отношение.
G>Но я лично сильно в этом сомневаюсь. Причины две. G>1) Нижележащие API (в частности, ОС) и библиотеки (включая динамические) могут быть написаны на разных языках, отличных от целевого, и уже поэтому convention неразумно делать частью стандарта конкретного языка. Создаст лишние сложности. G>2) Закладка в программе на порядок вычисления аргументов функции — сама по себе очень плохая практика. Это неочевидно, и хрен поймешь.
И стоит добавить третью причину. Если конвеншн определяет порядок вычисления — это сильно ограничивает современные оптимизаторы для компилируемых языков.
К примеру, компилятор может решить устроить замес из вычисления выражений в аргументах, с целью оптимально нагрузить конвейер. И если регистров дофига, и проц суперскалярно-конвейерный, то хороший компилятор так и поступит.
А если вызовы функций стоят в аргументах — он до кучи может решить их проинлайнить. Так может и JIT поступить в динамике.
А вот во времена Win 3.11 было все четко. Как в конвеншне указано положение в стеке — в таком порядке и считается. Ибо регистров мало, и один хрен не более одной инструкции за такт.