Существуют ли языки программирования без глобальных переменных?
Существуют ли языки, в которых область действия определена таким образом, что не распространяется на вложенные функции? Другими словами, есть ли язык, где код похож на следующий (Python-подобный синтаксис):
>>> x = 3
>>> def fact(n):
... print x
... return reduce(lambda u, v: u*v, xrange(1, n+1), 1)
...
выдаст ошибку, потому что х не определен внутри функции fact
?
В целом, существуют ли языки, в которых область действия любой функции не будет включать функции, определенные в ней?
Изменить: Спасибо за информативные комментарии. Причина, по которой я подумал об этом, заключается в том, что ситуация внутренней функции, имеющей доступ ко всей среде, обеспечиваемой ее содержащими функциями, кажется мне подозрительно близкой к ситуации, описанной Джо Армстронгом в его аргументе против ООП:
Поскольку проблема с объектно-ориентированными языками заключается в том, что у них есть вся эта неявная среда, которую они носят с собой. Вы хотели банан, но получили гориллу с бананом и джунглями.
Также важно, что я слышал, что у языка Newspeak нет глобального пространства имен, хотя я понятия не имею, как он работает.
Я могу представить себе проблему, поднятую в комментарии Брайана ниже, о встроенных функциях (функциях, импортированных из __builtins__
в Pythonspeak или System во многих других языках) искусственно вводится интерпретатором / компилятором в каждую функцию. Ведь с ними почти всегда обращаются специально на языке в первую очередь. Другой вариант - использовать их как методы объекта, передаваемого в качестве параметра функции или импортированного как модуль изнутри.
3 ответа
Я постараюсь в общих чертах описать, как это работает в Newspeak.
Любой код, который вы пишете, должен быть в модуле. Модуль является своего рода классом, так как в классах Newspeak могут содержаться другие классы, модуль по сути является классом верхнего уровня - классом, который не содержится в другом классе. Что особенного в Newspeak, так это то, что вы не можете ссылаться на что-либо за пределами вашего модуля.
Итак, как вы печатаете на консоли в Newspeak? Печать принадлежит классу Console (он же Transcript от Smalltalk), который является частью модуля Platform. Чтобы иметь возможность печатать на консоль, ваш модуль должен принять параметр конструктора Platform, получить консоль с платформы, сохранить консоль в слоте, а затем использовать ее для печати.
По сути, это похоже на внедрение зависимостей на уровне языка. Языковая среда разработки и среда выполнения помогут вам упаковать и загрузить программу, но если вам нужна более подробная информация - зайдите в блог Гилада Брачи, посмотрите этот пост, например, или посмотрите статью "Модули Newspeak".
PS Newspeak не является ни непрактичным, ни непригодным для использования, к сведению - он использовался в промышленной среде, и теперь вокруг него есть небольшое (но растущее) сообщество открытого кода. Конечно, Newspeak очень новый и развивающийся, но из личного опыта - писать программы довольно легко и увлекательно.
Я полагаю, что вы могли бы создать язык программирования, в котором глобальная область действия заменяется, например, ассоциативным массивом, содержащим функции и объекты, которые затем передаются в качестве рабочей среды для каждой вызываемой функции.
Рассмотрим следующий пример. В обычной Python-программе вы должны написать что-то вроде этого:
import foo
def square(x):
return x*x
print(square(int(raw_input("give a number: "))))
в программе без глобальных переменных вы бы предпочли написать что-то вроде этого:
def main(environment):
environment['import']('foo')
environment['square'] = lambda x: x*x
environment['print'](environment['square'](int(environment['raw_input']("give a number:"))))
и этот код будет выполняться в контексте что-то вроде этого:
def import_foo(modulename):
# dummy example
if modulename == 'foo':
import foo
environment = {
'import': import_foo,
'print': print,
'raw_input': raw_input
}
main(environment)
В программе с таким подходом и без глобальных функций функции в программе могут быть почти полностью изолированы от всего, кроме того, что они могут получить с помощью аргументов, которые получают. Затем вы могли бы также создать альтернативные среды для функций и затем запускать их в "тюрьмах". Библиотеки и функции будут похожи на электронные компоненты в цепи, где вам нужно, но также могут соединять части с тем, что вы хотите. Язык программирования, разработанный с учетом этого шаблона, может иметь некоторый синтаксический сахар для удобства, чтобы автоматически передавать неявную среду "по умолчанию" вызовам функций, но вы всегда можете явно заставить их использовать любую альтернативную среду, какую захотите.
Например, на глобальном языке, если у вас есть библиотека, предназначенная для доступа к данным в файловой системе или сети операционной системы, вы можете предоставить альтернативную среду и контролировать ввод-вывод или заставить библиотеку использовать свой собственный виртуальный файловая система или соединение VPN вместо обычной файловой системы и сети.
Реально, такая вещь никогда не могла бы существовать. Подумайте - когда вы печатаете на консоль, откуда берется этот дескриптор консоли? Когда вы ссылаетесь на функцию, откуда эта функция? Конечно, он не существует физически в стеке функции, из которой вы вызвали его. Это верно - это глобально. Реальность такова, что без глобальных переменных вы никогда не сможете сослаться на то, что не находится непосредственно в вашем стеке или куче, что означает отсутствие машинных инструкций, благодаря DEP. И для кучи, где бы вы взяли кучу? Вы не можете вызвать функцию ОС для выделения вам некоторой реальной новой памяти - это глобально.
Теоретически, вы могли бы создать такой язык или программу, но реальность такова, что это было бы больше похоже на Brainfuck, чем что-либо на самом деле пригодное для использования.