воскресенье, 30 сентября 2007 г.

Об областях видимости в языках программирования

Об областях видимости в языках программирования

Вчера в IRC на одном из каналов, которые я посещаю, зашёл очередной holywar на тему «Почему переменные в PHP, определённые в циклах, не остаются видимыми только в области цикла, а становятся видны и поза циклом?».





Я решил провести маленькую проверку на аналогичные вещи в других языках.

Насколько я знаю, в Perl как раз наоборот PHP-переменные, определённые внутри тела цикла, видны только в пределах цикла. И подтверждение этому следующий код:

my $a = 0;
for (my $a = 0; $a < 3; $a++) {
}
print $a, "n";

Ниже привожу фрагменты кода, что получились на c, c++, java, javascript:

c++:

#include <iostream>
#include <string>

using namespace std;

int main(int argc, char *argv[ ] ) {

    int a = 0;

    for (int a=0; a <= 2; a++ ) {
    }

    cout << "test a=" << a << endl;

}

c:

#include <iostream>
#include <string>

int main() {
        int a = 0;
        for (int a=0; a<= 2; a++ ) {}
        sprint("[%s]", a);
}
java:
public class testScope {
 public static void main(String[] args) {
  int a = 0;
  for (int a = 0; a < 3; a++) {}
  System.out.println(a);
 }
}

javascript:

var a = 0;
for (var a = 0; a < 3; a++) {}
alert(a);

Каковы итоги? Довольно неожиданны оказались для тех, кто утверждал, что такая реализация только в PHP.

Результаты:

Javascipt: вывел 3.

Java: ошибка на этапе компиляции: область внутри цикла является глобальной, поэтому переопределение ранее определённой переменной невозможно.
(cannot rediclare a)

C++: вывод на экран: test a=0

С: ошибка на этапе компиляции: область внутри цикла является глобальной, поэтому переопределение ранее определённой переменной невозможно.
(a.c:7: error: redefinition of ‘a’
a.c:6: error: previous definition of ‘a’ was here)

Код для с, с++ писался под FreeBSD, компилировался gcc и g++ соответственно. Для java был использован Eclipse. Javascript — Edit+ + браузеры.

Оказывается, что так, как это работает в Perl, так работает ещё только в c++, а, следовательно, PHP не является «еретиком» в плане такого поведения — он всего лишь «один из многих». А вот хорошо или плохо такое поведение — это уже, наверное, вопрос не этой заметки.

Автор: Станислав Малкин.

Интересное...



Комментарии:


Vyazovoi Says:
30.09.2007 в 20:43
А в чем собственно минус? Если сильно надо будет можно сделать unset
хотя я нуб, тонкостей незнаю, но вот узнать интересно.

anycolor Says:
30.09.2007 в 20:55
Vyazovoi, минус в засорении глобальной области видимости - и как результат - появление ошибок.

Vyazovoi Says:
30.09.2007 в 21:33
если давать уникальные имена переменным ошибок небудет ) Или взять за привычку делать ансет, хотя впринципе да - должно быть наоборот.

anycolor Says:
30.09.2007 в 21:54
Vyazovoi, unset это почти тоже самое, что в языке программирования следить за динамически выделяемой памятью - сколько не следи, все равно появляются ошибки. Поэтому unset - это вариант, но не очень хорошее решение.

Ni@m Says:
01.10.2007 в 00:25
Насчёт php - это действительно плохо. =/.
Засорение памяти, пространства имён и т.д.
Дело в том, что, насколько мне известно, php-интерпретатор не следит за ссылками на переменные - и если много подобных циклов и переменные везде разные имена имеют - ну тогда не шибко хорошо, хотя если корректно использовать функциональное программирование или ООП - то все будет гут.
Было сказано, что о такой как и все - не совсем - c, java - отказываются компилировать такой код - и правильно.
Видимостью переменной определённой внутри цикла вне его страдает ещё python и ruby - но им “простительно” - они корректно считают ссылки на свои переменные, таким образом память не загрязняется.
А с++/perl повели самым достойным образом - область видимость - это область видимости. =)

Dmitry Zhariy Says:
01.10.2007 в 15:28
В С++ очень активно используется автоуничтожение (автовызов его деструктора) при выходе из области видимости объекта.
Для С++ это очень важно… В Перле же я это свойство использовал в жизни только один раз. Пару минут назад, когда хотел попробывать, что оно работает :)
Вот код:
MyClass.pm
package MyClass;
sub new {
 print "I am constructor!\n";
 return bless {};
}
sub say_hello() {
 print "Hello!!!\n";
}
sub DESTROY {
 print "I am destructor!\n";
}
1;
test.pl
use MyClass;
use strict;
print "-" x 10, "This is the start!\n";
if (1) {
 my $object = new MyClass();
 $object->say_hello();
}
print "-" x 10,"This is the end";
Output:
----------This is the start!
I am constructor!
Hello!!!
I am destructor!
----------This is the end


Другие посты по этой теме:



Комментариев нет: