Здравствуйте, Курилка, Вы писали:
К>Здравствуйте, c-smile, Вы писали:
К>[cut] CS>>Как будет себя вести скажем Питон в аналогичном случае? CS>>"1" и "100"
К>А чего странного? К>Внутри функции в питоне создаётся локальная переменная и её значение возвращается функцией, всё более чем предсказуемо.
Здравствуйте, c-smile, Вы писали:
CS>if you will remove this line:
CS>
CS>if(false) { var somevar; }
CS>
CS>result in JS will be "1" and "1"
А блин, ты запутал с языками, приводишь код на JS с просьбой дать ответ, результат на tiscript, а вопрос про питон.
Поясни, как ты приведённую строку на питоне напишешь? Или питон был был так просто "до кучи", а претензии к JS?
CS>(попробуйте предсказать вывод тех alert()ов, ответ для ленивых в конце сообщения)
CS>Как будет себя вести скажем Питон в аналогичном случае?
"Аналогичного случая" для Питона не будет, потому что нет аналога двум действиям:
1. Какой-то код после return. За редчайшими исключениями, в Питоне все команды исполняемые.
2. Нет аналога оператору var. Необъявленная ранее переменная вводится имплицитно. Наоборот, для использования внешней переменной надо написать "global var" (если она на уровне модуля).
Поэтому — твой подход просто некорректен, а что ты решил назначить тут "аналогичным случаем" в Питоне — рассказывай сам (просто покажи код). Дальше посмотрим, аналогично это или нет.
CS>>(попробуйте предсказать вывод тех alert()ов, ответ для ленивых в конце сообщения)
CS>>Как будет себя вести скажем Питон в аналогичном случае?
N>"Аналогичного случая" для Питона не будет, потому что нет аналога двум действиям: N>1. Какой-то код после return. За редчайшими исключениями, в Питоне все команды исполняемые.
Не понял про "все команды исполняемые"... Можем переписать так
В JS как и в C/C++ identifier означает либо локальную переменную либо глобальную.
Проблема состоит в том что 1) все имена/перменные внутри функции попадают в один общий namespace и 2)
если где-то в недрах функции встретилось это имя с приставкой var то оно меняет суть *всех*
обращений к somevar втсретившихся и после и самое неприятное — до.
Такое решение представляется
1) конкретной засадой. Где-то в глубине функции кто-то напишет безобидный { var somevar; } и все — концов не найдешь в коде до него.
2) Означает что строго говоря прямая интерпретация JS невозможна — только через компиляцию и/или построение AST.
N>2. Нет аналога оператору var. Необъявленная ранее переменная вводится имплицитно. Наоборот, для использования внешней переменной надо написать "global var" (если она на уровне модуля).
CS>(попробуйте предсказать вывод тех alert()ов, ответ для ленивых в конце сообщения)
CS>Как будет себя вести скажем Питон в аналогичном случае? CS>Мой tiscript например выведет два раза "1".
JS печально известен своим идиотским правилом, что у него один scope на тело функции. Второго такого языка, возможно и нет. Починить это можно так (я как то переписывал код с JS и долго не мог понять зачем это нужно):
somevar = 100;
function test()
{
somevar = 1;
return somevar;
(function(){
if(false) { var somevar; }
})();
}
JavaScript: The Good Parts By Douglas Crockford:
...
JavaScript's syntax comes from C. In all other C-like languages, a block (a set of statements wrapped in curly braces) creates a scope. Variables declared in a block are not visible outside of the block. JavaScript uses the block syntax, but does not provide block scope: a variable declared in a block is visible everywhere in the function containing the block. This can be surprising to programmers with experience in other languages.
In most languages, it is generally best to declare variables at the site of first use. That turns out to be a bad practice in JavaScript because it does not have block scope. It is better to declare all variables at the top of each function.
Re: [js] А вот интересно ...>>JS печально известен своим идиотским правилом, что у него один scope на тело функции. Второго такого >>языка, возможно и нет. Починить это можно так (я как то переписывал код с JS и долго не мог понять >>зачем это нужно):
Ну какбы всякие Python, php тоже с таким вот идиотским правилом
Здравствуйте, meandr, Вы писали:
M>Re: [js] А вот интересно ...>>JS печально известен своим идиотским правилом, что у него один scope на тело функции. Второго такого >>языка, возможно и нет. Починить это можно так (я как то переписывал код с JS и долго не мог понять >>зачем это нужно):
M>Ну какбы всякие Python, php тоже с таким вот идиотским правилом:-))
Угу — по сравнению с ними Perl с его my выглядит значительно приятнее (я уж не вспоминаю, что local играет роль ещё и try-finally для замены переменной или элемента хэша). Питоновый вариант по сравнению с ним сильно урезан и крив. С другой стороны, само требование явно объявить необходимость доступа к внешней переменной через global является хорошей защитой от глупых ошибок...
CS>>?
N>Нет, не проходит компиляцию. Если бы проходило — было бы точно так же, как Вы описываете для JS. Указать как global нужно до первого использования.
А если в какой субблок засунуть?
Ну типа:
def test():
nlist = 1
if true:
global nlist
return nlist
(Не уверен за правильность нотации, извиняюсь, но мысль должна быть понятна)
Т.е. есть ли у Python block scopes? Или тоже все внавал лежит?
Здравствуйте, Mamut, Вы писали:
a>> ECMA-262, 3я редакция, раздел 12.2: a>>
a>> Блок не определяет новой области выполнения. Только Программа и ОбъявлениеФункции создают новую область видимости.
M>Но тогда описаное поведение жутко неявное. Получается, что локальность переменной определена только в конце функции, да еще после return'а...
Оно явно описано в разделе 10.1.3 той же спецификации:
Для каждого контекста выполнения имеется связанный с ним объект переменных. Переменные и функции, определённые в исходном тексте, добавляются в качестве свойств объекта переменных. Для кода функции параметры добавляются как свойства объекта переменных.
При входе в контекст выполнения свойства привязываются к объекту переменных в следующем порядке:
[...]
* Для каждого ОбъявленияПеременной или ОбъявленияПеременнойБезIn в исходном коде, создать свойство в объекте переменных с именем Идентификатора, указанного в ОбъявленииПеременной или ОбъявленииПеременнойБезIn, значение которого равно undefined и атрибуты которого определяются типом кода. Если в объекте переменных уже существует свойство с именем объявленной переменной, значение свойства и его атрибуты не изменяются. Семантически этот шаг должен следовать за созданием свойств для СпискаФормальныхАргументов и ОбъявленийФункций.
Таким образом все объявления переменных учитываются при входе в контекст, а лишь затем начинается выполнение кода.
Здравствуйте, anonymous, Вы писали:
A>Оно явно описано в разделе 10.1.3 той же спецификации:
A>Для каждого контекста выполнения имеется связанный с ним объект переменных. Переменные и функции, определённые в исходном тексте, добавляются в качестве свойств объекта переменных.
Это ты сам переводишь или где-то есть в электронном виде перевод?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
A>>Оно явно описано в разделе 10.1.3 той же спецификации: _FR>
A>>Для каждого контекста выполнения имеется связанный с ним объект переменных. Переменные и функции, определённые в исходном тексте, добавляются в качестве свойств объекта переменных.
_FR>Это ты сам переводишь или где-то есть в электронном виде перевод?
Здравствуйте, Mamut, Вы писали:
a>> Таким образом все объявления переменных учитываются при входе в контекст, а лишь затем начинается выполнение кода. M>Жесть, однако 0_о
Но вообще мало отличается от поведения, скажем, Pascal, за исключением того, что объявления могут быть разбросаны по всему коду.
Мне вот интересно, почему так было сделано: что контексты не порождаются блоками кода. Нигде не видел объяснения.
Здравствуйте, anonymous, Вы писали:
A>Здравствуйте, z00n, Вы писали:
Z>>JS печально известен своим идиотским правилом, что у него один scope на тело функции.
A>Почему идиотским?
Оно идиотское в контексте остального языка.
Язык обманчиво похож на С, а ведет себя как Pascal, при этом в паскале нельзя объявлять переменные где попало, а в JS можно. И еще то, что порядок объявления не важен.
С другой стороны с 75 года известен язык, похожий на JS (Scheme: первоклассные фукции etc.) в котором тоже единственным способом объявить блок является функция, но там ввели (by design) макрос let который позволяет прозрачно писать:
(let ((x 2)(y 3))
(* x y))
; вместо
((lambda (x y) (* x y)) 2 3)
Для более-менее сложных программ это бесконечный источник уродств и граблей.
//allow a node to propagate only once
c.once_e = function (maybeKeyNode, event)
{
if (!(event instanceof e.Node)) { throw 'once_e: expected Event as second arg'; } //SAFETYvar done = false;
return e.createNode(
maybeKeyNode,
[event],
(function () {
done = false;
return function (send, pulse) {
if (!done) {done = true; send(pulse); }
}; })());
};
Dave Herman (ex разработчик JS4)
Exercise:
1. Release a new version of a popular, commercial web browser.
2. In the new release, change the semantics of the web in some fundamental way--say, variable binding.
3. Break every scripted web page in existence, including Yahoo, eBay, GMail, you name it.
4. Try to convince users to upgrade to your new release.
Alternatively, try to convince major web application vendors to support two different semantics for your scripting language concurrently so their applications work in all popular releases of your browser. (Keep in mind it takes years before "legacy" browsers are no longer used on most desktops.)
Возвращаясь к исходному примеру: зачем вообще было разрешать писать стейтменты после return? В Lua, например, это была бы просто синтаксическая ошибка, и пришлось бы вводить отдельный блок для return:
function test()
local somevar = 1;
do
return somevar;
end
if false then local somevar; end
end
Здравствуйте, c-smile, Вы писали:
CS>(Не уверен за правильность нотации, извиняюсь, но мысль должна быть понятна) CS>Т.е. есть ли у Python block scopes? Или тоже все внавал лежит?
Нет. Наличие global где угодно делает имя глобальным еще до выполнения функции:
v = 100
def test():
print(v) # 100
v = 1
print(v) # 1return v
global v
print(test()) # 1print(v) # 1
Но только для этой функции (не для вложенных например)
Здравствуйте, Кодёнок, Вы писали:
Кё>Здравствуйте, c-smile, Вы писали:
CS>>(Не уверен за правильность нотации, извиняюсь, но мысль должна быть понятна) CS>>Т.е. есть ли у Python block scopes? Или тоже все внавал лежит?
Кё>Нет. Наличие global где угодно делает имя глобальным еще до выполнения функции:
"Нет" что? Нет block scopes?
Кё>
Кё>v = 100
Кё>def test():
Кё> print(v) # 100
Кё> v = 1
Кё> print(v) # 1
Кё> return v
Кё> global v
Кё>print(test()) # 1
Кё>print(v) # 1
Кё>
Кё>Но только для этой функции (не для вложенных например)
Мммм.... я прав что это та же хрень что и в JS?
Т.е. стоит где-то поглубже закопать 'global v' и что привет локальной дефиниции?
Здравствуйте, c-smile, Вы писали:
CS>Еще одна пеночка от Doug Crockford.
И это тоже описано в стандарте в разделе 7.9, касающемся автоматической расстановки точек с запятой:
[...]
Итоговые практические советы программистам на ECMAScript таковы:
* Постфиксный оператор ++ или -- должен появляться на той же строке, что и его операнд.
* Выражение в инструкциях return или throw должно начинаться на той же строке, что и токен return или throw.
* Метка в инструкцииях break или continue должна находиться на той же строке, что и токен break или continue.
Здравствуйте, z00n, Вы писали:
Z>>>JS печально известен своим идиотским правилом, что у него один scope на тело функции. A>>Почему идиотским? Z>Оно идиотское в контексте остального языка. Z>Язык обманчиво похож на С, а ведет себя как Pascal, при этом в паскале нельзя объявлять переменные где попало, а в JS можно. И еще то, что порядок объявления не важен.
Ну, это ни разу не объяснение. Существует огромное количество Си-подобных языков, с совершенно разным поведением, и вдруг они все становятся идиотскими.
Z>Возвращаясь к исходному примеру: зачем вообще было разрешать писать стейтменты после return?
Известно для чего, чтоб удобнее было стрелять в ногу. А если серьёзно, то после return можно, к примеру, наобъявлять локальных функций.
Здравствуйте, c-smile, Вы писали:
CS>Мммм.... я прав что это та же хрень что и в JS? CS>Т.е. стоит где-то поглубже закопать 'global v' и что привет локальной дефиниции?
Здравствуйте, anonymous, Вы писали: Z>>Язык обманчиво похож на С, а ведет себя как Pascal, при этом в паскале нельзя объявлять переменные где попало, а в JS можно. И еще то, что порядок объявления не важен.
A>Ну, это ни разу не объяснение. Существует огромное количество Си-подобных языков, с совершенно разным поведением, и вдруг они все становятся идиотскими.
В области языкостроения есть ряд вопросов, по которым достигнут консенсус. Блочные области видимости — это один из таких вопросов.
Здравствуйте, palm mute, Вы писали:
PM>В области языкостроения есть ряд вопросов, по которым достигнут консенсус. Блочные области видимости — это один из таких вопросов.
Естественно, такой список нигде не высечен в камне, но обсуждение на LtU, по-моему, закрывает эту тему.
Здравствуйте, c-smile, Вы писали:
Кё>>def test(): Кё>> print(v) # 100 Кё>> v = 1 Кё>> print(v) # 1 Кё>> return v Кё>> global v
Кё>>print(test()) # 1 Кё>>print(v) # 1 Кё>>[/python]
Кё>>Но только для этой функции (не для вложенных например)
CS>Мммм.... я прав что это та же хрень что и в JS? CS>Т.е. стоит где-то поглубже закопать 'global v' и что привет локальной дефиниции?
Компилятор действительно не различит, но проверять только компилятором для Питона — хуже чем моветон, это профнепригодность:) А вот pychecker такие вещи подробно комментирует:
$ pychecker 2.py
Processing module 2 (2.py)...
2.py:8: SyntaxWarning: name 'v' is assigned to before global declaration
global v
2.py:8: SyntaxWarning: name 'v' is assigned to before global declaration
global v
Warnings...
None
Поэтому подобная ситуация тривиально ловится, если заботиться о качестве кода.
Здравствуйте, Кодёнок, Вы писали:
Кё>Здравствуйте, c-smile, Вы писали:
CS>>Мммм.... я прав что это та же хрень что и в JS? CS>>Т.е. стоит где-то поглубже закопать 'global v' и что привет локальной дефиниции?
Кё>Да. Поэтому и варнинг выдается.
Ну т.е. та же проблема что и в JS.
В принципе для Python это не так критично ибо у него нет явно выраженных синтаксически scopes.
Но все равно, осадок остается. Но это субъективно конечно.
Вообще JS и Python и архитектурно (структура VM и runtime) и по идее своей очень близкие языки. Нотация разная — да, а так практически идентичны.
Здравствуйте, c-smile, Вы писали:
CS>(попробуйте предсказать вывод тех alert()ов, ответ для ленивых в конце сообщения)
Тут кстати нельзя не вспомнить Io, где можно просто вылезать куда хочешь — в локальный scope вызывающего, в global (Lobby), и т.п. без синтаксических заморочек:
x := 100
y := 200
z := 300
main := method(
x := 10
y := 20
z := 30
test := method(
x := 1
Lobby y := 2
call sender z := 3
x
)
writeln("local: test=", test, " x=", x, " y=", y, " z=", z)
)
main
writeln("global: x=", x, " y=", y, " z=", z)
Здравствуйте, palm mute, Вы писали:
PM>>В области языкостроения есть ряд вопросов, по которым достигнут консенсус. Блочные области видимости — это один из таких вопросов. PM>Естественно, такой список нигде не высечен в камне, но обсуждение на LtU, по-моему, закрывает эту тему.
О да, конечно, разве ж можно спорить с аргументацией типа «я к этому не привык». Придётся и вправду закрыть эту тему, раз нет более внятных аргументов.
Здравствуйте, anonymous, Вы писали:
A>Здравствуйте, c-smile, Вы писали:
CS>>Еще одна пеночка от Doug Crockford.
A>И это тоже описано в стандарте в разделе 7.9, касающемся автоматической расстановки точек с запятой:
Это хорошо что оно описано. Плохо (до полной ужасности) что оно вообще такое есть.
С grammar разрабатывалась прнципиально не чувствительной к CR-LF и их комбинациям.
Предполагается что это свойство наследуется всеми языками использующими её.
И это действительно так за единственным исключением — ECMAScript.
Абсолютно не понятно почему оно так собственно. Ради чего?
A>Итоговые практические советы программистам на ECMAScript таковы:
A>
A>[...]
A>* Постфиксный оператор ++ или -- должен появляться на той же строке, что и его операнд.
A>* Выражение в инструкциях return или throw должно начинаться на той же строке, что и токен return или throw.
A>* Метка в инструкцииях break или continue должна находиться на той же строке, что и токен break или continue.
Угу, вот так сказать more of those:
Когда Сатурн в Весах то код на JavaScript лучше не писать вообще. Переключитесь на нечто более предсказауемое, например CSS дизайн.
Здравствуйте, c-smile, Вы писали:
A>>И это тоже описано в стандарте в разделе 7.9, касающемся автоматической расстановки точек с запятой: CS>Это хорошо что оно описано. Плохо (до полной ужасности) что оно вообще такое есть. CS>С grammar разрабатывалась прнципиально не чувствительной к CR-LF и их комбинациям. CS>Предполагается что это свойство наследуется всеми языками использующими её. CS>И это действительно так за единственным исключением — ECMAScript. CS>Абсолютно не понятно почему оно так собственно. Ради чего?
Тут в «Веб программировании» постоянно приходится указывать пользователям, что JavaScript — не Java, похоже, пора указать и, что JavaScript — не C. JavaScript не использует грамматику Си, он использует грамматику, похожую внешне на грамматику Си, но другую. В нём пробельные символы напрямую влияют на семантику, это такая особенность, призванная превратить неверный код в верный.
Например будет прекрасно работать код:
if (something) alert('something')
else alert('nothing')
потому что он эквивалентен
if (something) alert('something');
else alert('nothing');
CS>Угу, вот так сказать more of those: CS>
CS>Когда Сатурн в Весах то код на JavaScript лучше не писать вообще. Переключитесь на нечто более предсказауемое, например CSS дизайн.
Нет, я не понимаю, что в JavaScript непредсказуемого (не необычного, а непредсказуемого) после прочтения спецификации?
Здравствуйте, anonymous, Вы писали:
A>Нет, я не понимаю, что в JavaScript непредсказуемого (не необычного, а непредсказуемого) после прочтения спецификации?
Я (и не только я, например Douglas Crockford ) говорю о качестве самой спецификации.
Ну не должно такое:
function foo()
{
return
{
ok:true
};
}
function foo()
{
return {
ok:true
};
}
генерировать разные результаты.
Этот semicolon injection это вообще недоразумение. Либо это ruby|lua|python|vb|etc. тип синтаксиса либо это C|C++|Java|Pike|Squirrel|etc.
Т.е. стоит в текст воткнуть символы \u2028 или \u2029 (которые далеко не всеми редакторами воспринимается как перевод строки, а просто как whitespace) и все — тот хрустальный замок можно только в качестве наждака использовать. Во всяком случае искать почему оно не работает можно до посинения.
Здравствуйте, c-smile, Вы писали:
CS>Либо это ruby|lua|python|vb|etc. тип синтаксиса либо это C|C++|Java|Pike|Squirrel|etc.
Почему?
CS>Т.е. стоит в текст воткнуть символы \u2028 или \u2029 (которые далеко не всеми редакторами воспринимается как перевод строки, а просто как whitespace) и все — тот хрустальный замок можно только в качестве наждака использовать. Во всяком случае искать почему оно не работает можно до посинения.
Да, а можно ещё кириллические буквы вместо латинских использовать.
M>>Re: [js] А вот интересно ...>>JS печально известен своим идиотским правилом, что у него один scope на тело функции. Второго такого >>языка, возможно и нет. Починить это можно так (я как то переписывал код с JS и долго не мог понять >>зачем это нужно):
M>>Ну какбы всякие Python, php тоже с таким вот идиотским правилом
N>Угу — по сравнению с ними Perl с его my выглядит значительно приятнее (я уж не вспоминаю, что local играет роль ещё и try-finally для замены переменной или элемента хэша).
Кстати, понятно почему — разрешение переменных по блокам — достаточно ресурсоемкий алгоритм, если язык компилируемый
это не сильно важно, т.к. не влияет на скорость работы скомпилированного кода, если язык интерпретируемый — то время компиляции и
время исполнения совпадают.
CS>Предполагается что это свойство наследуется всеми языками использующими её. CS>И это действительно так за единственным исключением — ECMAScript. CS>Абсолютно не понятно почему оно так собственно. Ради чего?
Руками парсер писали. Для быстродействия. И облажались. А потом объявили баг — фичей.
Здравствуйте, anonymous, Вы писали:
A>Здравствуйте, c-smile, Вы писали:
CS>>Либо это ruby|lua|python|vb|etc. тип синтаксиса либо это C|C++|Java|Pike|Squirrel|etc.
A>Почему?
"Патамучта" вот это вот все хорошо:
function foo() { return 0; }
function foo()
{ return 0; }
var baz = { bar: { ok: false } };
var baz =
{
bar:
{
ok: false
}
};
Здравствуйте, meandr, Вы писали:
M>Re[3]: [js] А вот интересно ... M>Perl потихоничку отмирает, с сожалению
Ну не знаю, к сожалению или без. Я на нём много писал, но с какого-то момента он задолбал так, что больше не хочется его использовать. Основные неприятности:
1. Нестрогая типизация скаляров, нет чёткой границы между числами и строками. Есть контексты, в которых это больно бьёт граблями. Последний встретившийся пример: экспорт в YAML стандартным модулем превратил строку типа "123000" в число, хотя это по контексту был префикс телефонного номера и не мог быть числом — приёмный парсер на этом обломался. Или вот "0" — false, а "00" — true. Я сравниваю с Питоном — там всё чётче: пересечь границу типов от строки к числу или наоборот можно только явно, типизация хоть и динамическая, но строгая.
2. Манера генерировать undef в массе случаев когда данных нет — вместо генерации исключения. Например, в Питоне получить элемент словаря с вылетом если его нет — "a[b]", а с возвратом None который аналог undef — "a.get(b,None)". В перле a{b} даёт возврат undef, если элемента нет, а для вылета надо писать или явный код проверки, или отдельную функцию. В результате программист обламывается писать проверки и генерирует код, который вместо адекватного действия гонит туфту.
3. Средства, удобные для программ размером в пару экранов, и средства, удобные для больших объёмов кода, резко различаются, а вторые — синтаксически громоздки. До какого-то размера можно использовать массивы и хэши напрямую, а после него — только по ссылке. А значит надо уже наворачивать скобки и кавычки. Есть определённый синтаксический сахар — сначала вместо ${$a}{b} придумали $a->{b}, затем вместо $a->{b}->{c}->{d} придумали $a->{b}{c}{d}, но всё это выглядит ужаснее, чем a.b.c.d, как в питоне и многих прочих. На сложном коде в глазах страшно рябит и работать с этим становится невозможно.
Конечно, есть и дофига хорошего. Но мне как-то от него пользы не было.:)