Ответ 1
Почему бы и нет? это лаконично, и это работает, в perl DWIM.
Скорее всего, так, потому что Ларри Стена понравилась именно так.
Мне интересно, почему создатели perl выбрали необычный синтаксис для печати в дескрипторе файла:
print filehandle list
без запятой после дескриптора файла. Я вижу, что он различает "список печати" и "список дескрипторов печати", но почему синтаксис ad hoc предпочтительнее для создания двух функций: один для печати на stdout и один для печати в заданный дескриптор файла?
В моих поисках я наткнулся на объяснение, что это косвенный синтаксис объекта, но не существовала ли функция печати в perl 4 и раньше, тогда как объектно-ориентированные функции приходили в perl относительно поздно? Кто-нибудь знаком с историей печати в perl?
Почему бы и нет? это лаконично, и это работает, в perl DWIM.
Скорее всего, так, потому что Ларри Стена понравилась именно так.
Поскольку запятая уже используется в качестве конструктора списка, вы не можете использовать ее для разделения семантически разных аргументов на print
.
open my $fh, ...;
print $fh, $foo, $bar
будет выглядеть так, как будто вы пытались напечатать значения трех переменных. Для парсера, который работает во время компиляции, нет способа сказать, что $fh
будет ссылаться на дескриптор файла во время выполнения. Поэтому для синтаксически (не семантически) вам нужен другой символ, чтобы различать необязательный дескриптор файла и значения для фактической печати этого дескриптора файла.
На этом этапе больше не нужно анализировать парсер, чтобы первый аргумент был отделен от второго аргумента пустым пространством, чем если бы он был отделен другим символом.
Если Perl использовал запятую, чтобы сделать print
больше похожим на функцию, файл-дескриптор всегда должен быть включен, если вы включаете что-либо для печати помимо $_
. Вот как работают функции: если вы передаете второй параметр, также должен быть включен первый параметр. В Perl не существует одной функции, в которой первый параметр является необязательным, если существует второй параметр. Взгляните на split. Его можно записать с использованием от нуля до четырех параметров. Однако, если вы хотите указать <limit>
, вы должны также указать первые три параметра.
Если вы посмотрите на другие языки, все они включают в себя два разных способа печати: один, если вы хотите STDOUT, а другой, если вы печатаете что-то помимо STDOUT. Таким образом, Python имеет как print
, так и write
. C имеет как printf
, так и fprintf
. Тем не менее, Perl может сделать это только с одним выражением.
Посмотрите на инструкцию печати немного ближе - вспомните о 1987 году, когда Perl был впервые написан.
Вы можете представить себе синтаксис print
, который действительно существует:
print <filehandle> <list_to_print>
Чтобы печатать на OUTFILE
, вы бы сказали:
Чтобы напечатать этот файл, вы должны сказать:
print OUTFILE "This is being printed to myfile.txt\n";
Синтаксис почти по-английски (PRINT to OUTFILE строка "Это печатается в myfile.txt\n"
Вы также можете сделать то же самое с STDOUT:
print STDOUT "This is being printed to your console";
print STDOUT " unless you redirected the output.\n";
В качестве ярлыка, если дескриптор файла не был указан, он будет печатать в STDOUT или любом дескрипторе файла, на котором установлено select.
print "This is being printed to your console";
print " unless you redirected the output.\n";
select OUTFILE;
print "This is being printed to whatever the filehandle OUTFILE is pointing to\n";
Теперь мы видим мышление за этим синтаксисом.
Предположим, у меня есть программа, которая обычно печатает на консоли. Тем не менее, мой босс теперь хочет, чтобы часть этого вывода была напечатана в различные файлы, когда это необходимо, вместо STDOUT. В Perl я мог бы легко добавить несколько избранных утверждений, и мои проблемы будут решены. В Python, Java или C мне пришлось бы модифицировать каждый из моих операторов печати и либо иметь некоторую логику, чтобы использовать запись файла в STDOUT (что может включать некоторые зависания при открытии и обновлении файла в STDOUT.
Помните, что Perl не был написан как полноценный язык. Было написано, чтобы сделать быструю и грязную работу по анализу текстовых файлов более легко и гибко, чем awk. На протяжении многих лет люди использовали его из-за его гибкости, а новые концепции были добавлены поверх старых. Например, перед Perl 5 не было таких вещей, как ссылки, что означало, что не существует такой вещи, как объектно-ориентированное программирование. Если бы мы, вернувшись во времена Perl 3 или Perl 4, нуждались в чем-то более сложном, чем простая переменная list
, hash
, scalar
, мы должны были ее самостоятельно выполнить. Не похоже, что сложные структуры данных были неслыханными. C имеет структуру с момента ее первоначального начала. Черт, даже Паскаль имел концепцию с записями еще в 1969 году, когда люди думали, что колокольчики были классными. (Мы умоляем безумие. Мы все были на наркотиках.) Однако, поскольку ни оболочка Борна, ни awk
не имели сложных структур данных, то зачем им Perl их нужно?
Ответ на "почему", вероятно, субъективен и что-то близкое к "Ларри понравилось".
Обратите внимание, однако, что косвенная нотация объектов не является признаком print
, а общей нотацией, которая может использоваться с любым объектом или классом и методом. Например, с помощью LWP::UserAgent
.
use strict;
use warnings;
use LWP::UserAgent;
my $ua = new LWP::UserAgent;
my $response = get $ua "http://www.google.com";
my $response_content = decoded_content $response;
print $response_content;
Всякий раз, когда вы пишете method object
, это означает точно то же, что и object->method
. Обратите также внимание на то, что синтаксический анализатор работает только надежно, пока вы не вставляете такие обозначения или не используете сложные выражения для получения объекта, поэтому, если вы не хотите иметь массу удовольствия с помощью скобок и цитат, я бы рекомендовал не использовать его в любом месте, кроме обычных случаев print
, close
и остальных методов ввода-вывода.