программирование
Сравнение объектов встроенных типов в Пайтоне
Некоторым ребятам показалось, что в заметке про «goatse operator» в Перле я поругал этот язык. Это не так, можно прочитать заметку от и до, чтобы в этом убедиться. Мне очень нравится Перл, но это язык не для современного продакшна. Давайте я
В Пайтоне всё что только можно — объект и нет примитивных типов. С объектами можно делать всё что хочется — сравнивать, умножать, производить битовые операции. Чтобы программист мог указать как объекту следует себя вести рядом
In [26]: "Это строка".__eq__
Out[26]: <method-wrapper '__eq__' of str object at 0x10136f770>
In [27]: "Это строка".__ne__
Out[27]: <method-wrapper '__ne__' of str object at 0x10139cf70>Сравнивать между собой можно большинство встроенных типов — список с со словарём, строку с кортежем и так далее. Есть исключения (например, set нельзя сравнить ни с чем, кроме set и frozenset), но их мало. Какой же будет результат сравнения? Давайте попробуем:
In [44]: "">()
Out[44]: False
In [45]: ""<()
Out[45]: True
In [46]: []>()
Out[46]: False
In [47]: []<()
Out[47]: True
In [48]: []<{}
Out[48]: False
In [49]: []>{}
Out[49]: TrueДаже пустые объекты разных типов не равны между собой,
In [52]: [1,2,3,4,5,6]<(0,)>[100000]
Out[52]: TrueНе знаю где это написано в документации, не искал, но я совершенно случайно,
True < {} < [] < object() < "" < () < u""
# b < d < l < o < s < t < uРешение мне кажется, мягко говоря, неудачным, но уж какое выбрали. Я не вижу ничего страшного в том, чтобы сравнение встроенных типов всегда выдавало False (попробуйте сравнить между собой два None) или выдавать исключение при попытке их сравнения (кажется
location.reload() ≠ location.href=location.href
Увидел у Никиты Васильева во внутренних бложиках, что вызов «location.reload()» не эквивалентен присваиванию location.href в себя же. Оказывается, последний перезагружает страницу из кеша во всех браузерах, кроме «Оперы».
Оператор goatse в Перле
Внезапно вспомним Перл.
Есть такая шутка, что Перл единственный язык, программа на котором до и после
not exp log srand xor s qq qx xor
s x x length uc ord and print chr
ord for qw q join use sub tied qx
xor eval xor print qq q q xor int
eval lc q m cos and print chr ord
for qw y abs ne open tied hex exp
ref y m xor scalar srand print qq
q q xor int eval lc qq y sqrt cos
and print chr ord for qw x printf
each return local x y or print qq
s s and eval q s undef or oct xor
time xor ref print chr int ord lc
foreach qw y hex alarm chdir kill
exec return y s gt sin sort splitЕсли не верите, попробуйте запустить, ничего страшного не произойдёт. Очень много шуток есть по поводу того, каким ненатуралом надо быть, чтобы программировать на этом языке и в этом тоже есть доля правды.
Я постараюсь пропустить неаппетитные подробности, но есть такой мем «goatse» — это картинки мужичка, в деталях показывающего свою тёмную неизвестность, а так же пародии на неё. Не гуглите пожалуйста это, прошу, нет, даже умоляю, не надо. Та картинка, как любой
Для нас важно, что после того как картинка стала мемом, появился смайлик „=()=“, довольно точно отражающий её суть. Я знаю эту преамбулу, потому что однажды
Например, вам нужно подсчитать сколько цифр содержится в строке. На помощь вам придёт goatse operator!
my $s = "Hello, world! This is a Perl! 123456";
my $c =()= $s =~ /\d/g;
print $c;В результате будет напечатано число шесть.
Как это работает и почему нельзя
Сначала отвечу на первую часть.
Самое правое выражение в рассматриваемой строчке — регулярное выражение, которое ищет одну цифру, оператором «=~» мы применяем его к конкретной переменной, а ключ «g» в конце регулярки говорит, что искать надо все вхождения.
В Перле есть понятие скалярного и списочного контекста. Результат может сильно отличаться в зависимости от того ожидается ли
Например, если я попробую напрямую присвоить результат выполнения регулярного выражения на переменной „s“ в скалярную переменную (начинается с доллара), то я получу флаг, показывающий встретились ли вообще цифры в рассматриваемой переменной. Если же присвоить тот же результат массиву (имя переменной начинается с «@»), то я получу массив совпадений.
С goatse operator происходит следующее.
На деле «() =
Получается «SCALAR = LIST0 = LISTREGEXP», что возвращает нам количество элементов массива LISTREGEXP при любом не константном LIST0. Двумя присваиваниями, идущими подряд, вряд ли
Теперь ответ на второй вопрос. Нельзя ли
my $s = "Hello, world! This is a Perl! 123456";
my @c =$s =~ /\d/g;
print scalar @c; # массив в скалярном контексте вернёт количество элементовНо это скучно.
33000 и анимированный GIF

По всей видимости, «Опера» немного неправильно обрабатывает анимированные «гифы».
Анимированный GIF устроен очень просто — поверх первого кадра через заданное время лепится следующий. Задержка задаётся в сотых долях секунды и, согласно спецификации, поля для её хранения имеет размер беззнаковое слово (2 байт), то есть максимальное значение — 655,35 секунд или почти 11 минут.
Распространённая ошибка в Си и похожих языках — использовать вместо беззнакового число со знаком. Тогда максимальное значение по модулю сокращается в два раза.
Вот я и проверил — не содержат ли кодеки популярных браузеров эту ошибку. На картике — число «1», если оно через
У меня на ноуте на FF 5, Safari 5.0.5, Chrome 12.0.742.122 цифра меняется, а на «Опере» 11.50 — нет. Сейчас попробую найти ноут с Windows 7 и попробую там. Попробуйте тоже на своих браузерах.
Добавлено: меняются ещё цифры на Андроиде 2.3.4, на FF 4.0.1 (Windows), а так же под Internet Explorer 9.0 и 10PP2 (Windows 7).
Добавлено ещё позднее: всё в порядке у «Оперы», разъяснил один из читателей — «Опера» начинает анимацию заново, если GIF не было видно. Дожидаясь, я переключал табы, поэтому анимация стартовала всегда сначала и «2» не появлялась. Так что ложная тревога, но любопытный факт.
В IE10 не будет попадать под conditional comments
«Микрософт» решила, что conditional comments не должны обнаруживать IE10. То есть, по идее, условия «[if IE]», «[if IE 10]», «[if IE gt 5]» работать не должны, а «[if IE lte 9]»
Поведение изменено
Because some features in earlier versions of IE aren’t compatible with HTML5 parsing, we’ve removed them from IE10 mode. Sites that rely on these legacy features will still work when running in legacy modes. This way, sites that work today will continue to work with IE10 even if the developers of the site don’t have the time to update them.
Причём «Микрософт» тут же признаётся, что парсер ни при чём:
This means conditional comments can still be used, but will only target older versions of IE.
Если часть условия conditional comments
Скорее «Микрософт» этим шагом заявляет, что «мы так всё идеально поддерживаем, что нет нужды отделять IE от других браузеров». Может быть это и так. Но я был бы рад, если бы conditional comments появились в других браузерах, а не исчезли был из IE.
Помимо этого из IE10 исчезнут Element Behaviors и XML Data Islands.
Добавлено позднее: мы тут поговорили с Вадимом Макеевым, кажется, я ошибаюсь. В режимах эмуляции старых браузеров (вероятно в этот момент работает отдельный движок), conditional comments работают, в режиме IE10 — нет.
Галереи теперь в трансляциях
Сделал, как многие просили, фотогалереи в трансляциях RSS. Теперь всюду, куда транслируется мой блог («Ярушка», ЖЖ и т. д.), видно бо́льшую часть фотографий (не более десяти). Галереи там, конечно, условные — с миниатюры ссылка ведёт на полное фото.

Вот, кстати, о чём совершенно забыли создатели современной версий HTML — это форматирование HTML там, где всё плохо с CSS. В читалках RSS (тут CSS режется из соображений безопасности) и почтовых клиентах (те же соображения, плюс примитивные движки в некоторых приложениях). Я, пока отлаживал трансляции, убедился, что единственный способ всё отформатировать как надо — использовать таблицы и винтажные 0.gif. Но чем дальше, тем меньше можно сделать атрибутами тегов, да ещё и в условиях, когда лента встроена в документ, где уже есть стили (например
Конечно это правильно, разделение данных и представления, но HTML5 не предлагает взамен безопасного внедрения чужого контента в изолированном окружении, что полностью решило бы проблему. Есть специальный режим у IFRAME, но фреймы — это совсем не то, они не ведут себя как часть страницы, скорее как окошко в другой документ. Полосы прокрутки, развыв выделения текста и так далее. Всё не то.
Как мне AppleScript
Миша, мой коллега, под постом, где я написал про интерпретатор Brainfuck на AppleScript с беспокойством осведомился, не подсел ли я на AppleScript.
Краткий ответ: нет.
Длинный ответ таков.
Мне непонятно текущее состояние AppleScript. Очевидно, что концепция «пользователь пишет программы на английском» вполне себе ничего. Для непрограммистов это был бы выход. А для программистов такой язык жутко неудобен. По понятными причинам. Программисты привыкли писать много, а на велиречивом AppleScript писать не каждому понравится (не пишу «никому», потому что существует же Objective C). Все эти сокращения в языке — «собачки», доллары и разные скобочки, их нужно помнить, но они здорово экономят время при написании программы и при её чтении. Потому что они короткие и их больше помещается на экране.
Текущее состояние непонятно, потому что цели своей авторы языка не достигли. До сих пор нужно писать «set Var to Var + 1» и нельзя «set Var to Var plus one», какой же это английский? При этом язык уже полтора года не развивается.
То есть проблема «иногда быстро писать мелкие программы» явно пока не решена. Так как для этого «иногда» надо иметь память робота, чтобы вспомнить через несколько месяцев как в этом языке
Например, чтобы вызвать текстовый редактор и написать там «Hello», нужно сделать следующее:
tell application "TextEdit"
activate
tell application "System Events" to keystroke "hello"
end tellЯ открываю приложение TextEdit (так встроенный в MacOS текстовый редактор называется) и прошу System Events понажимать в редактор несколько клавиш. Выделенное наклонным — это как раз пример такого API. Причём, если написать в кавычки «³˚¹⁄₃¹⁄₂», то программа либо не сделает ничего, либо напечатает в редактор ерунду. Всё устроено так, как будто System Events действительно жмёт клавиши на клавиатуре. А вот эти символы система не знает как ввести. То же будет с китайскими иероглифами, например.
Ещё, когда я только начал знакомиться с AppleScript, у меня было заблуждение, что AppleScript — язык общего назначения, вроде PowerShell или Bash. Ничего подобного, вместо bash в Mac OS есть bash. AppleScript толком не умеет даже получить данные от пользователя, скажем перехватить нажатие клавиши (и нет ничего встроенного, что может ему в этом помочь), а уж о том, как мало он умеет самостоятельно выводить и говорить нечего.
Так что симпатии к языку у меня не появится, думаю. Не для меня он. Но писать я на нём иногда буду, я и на CMD много странного писал в своё время.
Brainfuck на AppleScript
Для развлечения написал интерпретатор языка Brainfuck на AppleScript.
Особенности: для ввода программы используется текстовое поле, которое выглядит как однострочное, но на деле понимает многострочный текст. Операция «,» у меня с буфером, это значит, что при запросе можно вводить сразу строку, при надобности интерпретатор сам будет брать оттуда значения. Если их не хватит, запросит ещё.
AppleScript медленный язык, следовательно и получившийся интерпретатор медленный (никаких оптимизаций я не делал), лучше всего на нём запускать небольшие программы. Например, «Hello, world»:
++++++++[>+++++++++<-]>.<+++++[>++++++<-]>-.+++++++..+++.<
++++++++[>>++++<<-]>>.<<++++[>------<-]>.<++++[>++++++<-]>
.+++.------.--------.>+.Не уверен, что нигде не ошибся Интерпретатор Brainfuck на AppleScript.
#!/usr/bin/osascript
-- AppleScript Brainfuck interpreter
-- Evgeny Stepanischev 1 Jul 2011 //bolknote.ru
set Cells to {}
repeat 30000 times
set end of Cells to 0
end repeat
display dialog "Enter your BF program" default answer ""
set Bf to text items of text returned of result
set Pointer to 1
set CmdPointer to 1
set Output to ""
set Input to {}
set Stack to {}
repeat while CmdPointer ≤ (count of Bf)
set Cmd to item (CmdPointer) of Bf
if Cmd is equal to ">" then
set Pointer to Pointer + 1
if Pointer > 30000 then set Pointer to 1
else if Cmd is equal to "<" then
set Pointer to Pointer - 1
if Pointer < 1 then set Pointer to 30000
else if Cmd is equal to "+" then
set Val to (item (Pointer) of Cells) + 1
if Val is greater than 255 then set Val to 0
copy Val to item (Pointer) of Cells
else if Cmd is equal to "-" then
set Val to (item (Pointer) of Cells) - 1
if Val is less than 0 then set Val to 255
copy Val to item (Pointer) of Cells
else if Cmd is equal to "." then
set Output to Output & (ASCII character item (Pointer) of Cells)
else if Cmd is equal to "," then
if Output ≠ "" then
display alert Output
set Output to ""
end if
if Input is {} then
display dialog "Enter one or more characters" default answer ""
set Res to text returned of result
set item (Pointer) of Cells to ASCII number of character 1 of Res
try
set Input to rest of text items of Res
end try
else
set item (Pointer) of Cells to ASCII number of item 1 of Input
set Input to rest of Input
end if
else if Cmd is equal to "[" then
if item (Pointer) of Cells = 0 then
set CmdPointer to CmdPointer + 1
set Deep to 1
repeat while CmdPointer ≤ (count of Bf)
set Cmd to item (CmdPointer) of Bf
if Cmd is equal to "[" then
set Deep to Deep + 1
else if Cmd is equal to "]" then
set Deep to Deep - 1
if Deep is 0 then exit repeat
end if
set CmdPointer to CmdPointer + 1
end repeat
else
set Stack to (CmdPointer - 1) & Stack
end if
else if Cmd is equal to "]" then
if item (Pointer) of Cells ≠ 0 then
copy item (1) of Stack to CmdPointer
end if
set Stack to rest of Stack
end if
set CmdPointer to CmdPointer + 1
end repeat
if Output ≠ "" then
display alert Output
end if
Рабочая задача: карта + объекты
Ничего экстраординарного, просто задача по работе попалась.
Дана карта местности (картинка), на неё нанесено большое количество объектов, несколько тысяч. В каждый объект можно тыцнуть мышкой, карта большая, её надо позволять «таскать» мышкой.
Текущее решение тормозит, а надо сделать так, чтобы не тормозило.
У меня была гипотеза, что если нарисовать всё это дело на большущем CANVAS, выходящем за пределы экрана и позволить его таскать мышкой, то тормозит не будет.

При клике происходит поиск объекта по списку (безо всякой оптимизации пока), если объект найден, то выводит информацию по цвету, если зажать кнопку мыши, срабатывает флаг «пользователь желает тащить», если пошевелить в этот момент мышью, координаты CANVAS будут меняться вслед за мышью.
Вроде не тормозит, хороший способ делать карты. Делюсь, вдруг пригодится кому.
Часы без JavaScript: фильм о фильме
Как уже догадались все, кому это было хоть каплю интересно, часы без JavaScript сделаны анимированным GIF. Сделал я всё очень просто: скачал найденный

Оказалось, что проще всего сгенерировать картинки при помощи Go. В Пайтоне на «Маке» у меня нет PIL и я его плохо знаю, во встроенном PHP нет поддержки TTF, так что Go:
package main
import "gd"
import "os"
import "fmt"
func main() {
im := gd.CreateTrueColor(21, 21)
white := im.ColorAllocate(255, 255, 255)
black := im.ColorAllocate(0, 0, 0)
// стрелки: 64 → 123 (m) и 192 → 251 (h)
defer im.Destroy()
for i := 0; i < 720; i++ {
im.FilledRectangle(0, 0, 20, 20, white)
min := i % 60
hour := (i / 60) * 5 + min / 12
im.StringFT(black, "./clock.ttf", 10, 0, 0, 16, "1")
im.StringFT(black, "./clock.ttf", 10, 0, 0, 16, string(hour + 192))
im.StringFT(black, "./clock.ttf", 10, 0, 0, 16, string(min + 64))
name := fmt.Sprintf("gifs/%02d%02d.gif", i/60, i%60)
im.Gif(name)
}
}После запуска получилось 720 картинок с ноль часов ноль минут до 11:59 (я не зря выбрал часы со стрелками, это позволило сократить размер анимированных часов вдвое).
Когда на сервер приходит запрос, я проверяю сколько сейчас времени и, если файл с часами для текущей минуты уже существует, то делаю редирект на существующую картинку. Если нет, то генерирую из 720 картинок новый «мультик», кладу его на диск и делаю редирект на него (остальные картинки удаляю):
<?
include "clock.inc.php";
list($h, $m) = explode(':', date('H:i'));
if ($h > 12) $h -= 12;
$name = sprintf("%02d%02d.gif", $h, $m);
if (!file_exists($name)) {
@array_map('unlink', glob('*.gif'));
$frames_tail = $frames = $framed = array();
$frames_name = 'frames_tail';
for ($H = 0; $H<12; $H++) {
for ($M = 0; $M<60; $M++) {
if ($h == $H && $m == $M) {
$frames_name = 'frames';
}
${$frames_name}[] = sprintf("gifs/%02d%02d.gif", $H, $M);
$framed[] = 100;
}
}
$frames = array_merge($frames, $frames_tail);
$gif = new GIFAnimator($frames, $framed, 0, 2, -1, -1, -1, 'url');
fwrite(fopen($name, 'wb'), $gif->GetAnimation());
}
header("Location: $name");Для генерации анимированных GIF применяется
Часы без JavaScript
Сделал крошечные аналоговые часы, которые работают без JavaScript. Кто первый догадается как они работают, тот молодец.
Правда я их ускорил в 60 раз (а то очень уж скучно смотреть), поэтому это скорее секундомер, но стартуют они с текущего времени.
Текстовые ссылки в графике

Читая последнюю, на настоящий момент, статью в Ководстве Лебедева «Правила оформления ссылок» обратил внимание, что Студия в этом месте, вроде как, не всегда следует своим же советам.
В правом верхнем углу располагается логотип Студии, являющийся ссылкой, где текстом написано «Студия Артемия Лебедева». Я понимаю, что это картинка, но простой пользователь этого не поймёт, да и какая разница — текст есть текст, прорендерен ли он заранее в графике или это сделала операционная система позже.
Написал письмо Артемию, посмотрим что ответит.
Технических трудностей, между тем, в подчёркивании таких ссылок никаких — прочертил линию в графике и всё, ссылка подчёркнута. Другое дело в подствечивании при наведении, кажется что это невозможно. Но это только на первый взгляд. Я уже демонстировал (неоднократно), что это делается очень просто.
Такие опыты я производил четыре года назад, так даже постоянные читатели вряд ли помнят. В GIF или PNG под ссылкой «прорезается» (прочерчивается прозрачным) полоска, которая будет имитировать наше подчёркивание. Картинке в CSS ставится фон ссылки (например, синий), при наведении фон меняется, схематически:
img {
background: blue;
}
img:hover, img:visited {
background: red;
}Google Go vs. Си
Ребята на работе
Я подключился и написал пример на Google Go:
package main
import "fmt"
func main() {
x := []int{2}
for i := 3; i < 200000; i += 2 {
simple := true
for _, j := range x {
if i % j == 0 {
simple = false
break
}
}
if simple {
x = append(x, i)
}
}
fmt.Println(x)
}Запускалось всё
Python — 25,95 секунды Perl — 22,96 секунды PHP — 21 секунда Objective C — 9,40 секунды JavaScript (V8) — 4,73 секунды Java — 1,94 секунды Си — 0.95 секунды Google Go — 0,71 секунды.
Особенно меня поразили «Гоу» и JavaScript.
JS CSS в одном файле у меня на сайте
Я
Особых трудностей не встретил, только убрал все комментарии из файлов с JavaScript руками и добавил удаление BOM из файлов, браузеры
Схема,
Вот ещё тонкость, обязательно нужно добавить новый
AddType */* .cssjsОказалось, что последний «Хром» ни в какую не хочет рендерить CSS с таким типом, пришлось заменить на «text/css,*/*» на «text/css», предыдущий вариант не работал в IE9.
Надо посмотреть как отнесётся к этому второй FF, а пока, если у вас «Хром» или IE9 и показывает неправильно, обновите, пожалуйста, страницу, чтобы она не из кеша взялась, всё должно нормально отрендериться.
Посмотрим «в поле» насколько это стабильно работает.
почемужеонинеговорятпорусски
RFC 3492 «Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)» описывает punycode, это такой способ кодирования национальных доменов, вроде «президент.рф» или «
Так вот, в этом RFC есть примеры кодирования фраз на разных языках в punycode, есть и русский:
(I) Russian (Cyrillic):
U+043F u+043E u+0447 u+0435 u+043C u+0443 u+0436 u+0435 u+043E
u+043D u+0438 u+043D u+0435 u+0433 u+043E u+0432 u+043E u+0440
u+044F u+0442 u+043F u+043E u+0440 u+0443 u+0441 u+0441 u+043A
u+0438
Punycode: b1abfaaepdrnnbgefbaDotcwatmq2g4lА вот что там написано:
bolk-osx:~ bolk$ python -c 'print "xn--b1abfaaepdrnnbgefbaDotcwatmq2g4l".decode("idna")'
почемужеонинеговорятпорусскиЧерновики у меня в комментариях
Мне тут хочется пару проектов на PHP доделать, а я
В том числе сделал то, что давно просили — черновики в комментариях. Работает только в современных браузерах — IE 8.0+, FF 3.5+, Safari 4.0+, Chrome 4.0+, Opera 10.5+, а так же iOS 2.0+ и Андроид 2.0+. Только такой список, так как сохранение происходит в localStorage.
localStorage — это клиентская база данных «ключ и значение», которые есть сейчас уже во всех распространённых браузерах. Преимущество хранения черновиков именно в ней — черновик сохраняется вне зависимости от того рухнул сервер или нет, ведь localStorage сохраняет данные на диске клиента.
Кстати, я делал библиотеку эмуляции localStorage для IE 6 и 7 (используется behavior userData), но у себя использовать не буду, ни к чему поощрять некрофилию.
Работает всё следующим образом (детально можно посмотреть в исходниках любой страницы с комментариями): когда пользователь делает паузу в наборе комментария, мой JS вызывает localStorage.setItem, где ключём является URL страницы плюс имя поля (у меня их три — имя пользователя, сам комментарий и кому этот комментарий был адресова).
После отправки комментария в теле полученной страницы приходят вызовы localStorage.removeItem, которые удаляют сохранённые значения.
Наконец, если страница была загружена не в результате отправки комментария, вызываются localStorage.getItem, чтобы получить сохранённые значения и подставить их в соответствующие поля.
Код, с использованием JQuery, получился вот такой:
// globalStorage — это для FF 2.0, но я не уверен, что это правда работает
var storage = window.localStorage || window.globalStorage && window.globalStorage[location.hostname] || null;
if (storage) {
var savedraft = function s() {
if (s.hnd) {
clearTimeout(s.hnd);
}
var o = $(this);
s.hnd = setTimeout(function() {
try { // если не хватит места, будет исключение
var prefix = location.pathname + '#';
storage.setItem(prefix + o.attr('name'), o.val());
storage.setItem(prefix + '?', +new Date()); // сохраняю время, возможно в будущем буду подчищать старые черновики
} catch (o) {}
}, 500);
}
// каждый элемент, который надо сохранять, имеет класс draft
$.each($('.draft'), function(_, value) {
var o = $(value),
key = location.pathname + '#' + o.attr('name'),
v = storage.getItem(key);
if (savedsuccessfully) { // внешний флаг, что черновик больше не нужен — всё сохранено на сервере
storage.removeItem(key);
} else if (v !== null) {
o.val(v);
}
o.keypress(savedraft).change(savedraft);
})
}localStorage не резиновое, у разных браузеров значения различаются, но в целом, там около 5МБ на домен, да и диск пользователя забивать жалко. Поэтому я сохраняю время записи, возможно
99 бутылок: Go
48. Go — язык программирования, придуманный в «Гугле». Я на нём программирую, время от времени, и довольно неплохо его уже знаю. Замечательный, на мой взгляд, язык. Этакий «Си с человеческим лицом». Особенно интересно добавлено туда ООП, да и параллельные вычисления сделаны хорошо. Единственно — не нравится реализация обработки ошибок через panic/defer.
Язык статический, строгой типизации, компилируемый. Кстати, одна из особенностей языка — исключительно быстрая компиляция.
Некоторые ребята считают, что он похож на «Паскаль». Думаю это
package main
import "strconv"
func main() {
for i := 99; i>0; i-- {
b := bottles(i) + " of beer"
println(b + " on the wall, " + b + ".")
println("Take one down and pass it around, " + bottles(i-1) + " of beer on the wall.\n")
}
println("No more bottles of beer on the wall, no more bottles of beer.")
println("Go to the store and buy some more, 99 bottles of beer on the wall.")
}
func bottles(beer int) string {
switch (beer) {
case 0:
return "no bottles"
case 1:
return "1 bottle"
}
return strconv.Itoa(beer) + " bottles"
}Перевёл свой сайт на PHP 5.3.4
Решил поднять свои старые проекты на PHP под MacOS, чтобы на ноуте их нормально разрабатывать. В том числе, перетащил свой сайт. У меня движок сплошной эксперимент, так что используются различные тонкие вещи (например, ленивые вычисления при помощи __toString), которые в PHP 5.3 (который у меня на «Маке»)
Мелочи вспоминать не хочется, из того что запомнилось — PHP 5.3 нервно,
С веткой PHP 5.3 я почти не работал, когда эта версия стала появляться в пакетах стабильных версий систем, я уже перешёл на «Пайтон».
«Go»: недостатки
Я уже успел написать на «Go» пару тысяч строк (не считая удалённого кода) и должен сказать, что этот язык мне нравится. Этакий «Си» с человеческим лицом. Правда обработка ошибок через panic/defer мне до сих пор кажется сомнительным удовольствем.
Почему же этот язык столько непопулярен?
Самая главная — язык до сих пор не стабилизировался. К пример, пятого мая этого года вышел релиз №57), где кардинально изменился способ которым можно проверить закрылся ли канал. Вместо функции closed канал просто возвращает два значения. Из других примеров могу вспомнить как после очередного обновления компилятора мне пришлось везде в коде заменить вызов Open на OpenFile.
Вторая сильная причина — мало документации. По языку есть только одна книга, о которой мало кто знает (кстати, рекламирую: «Learning Go» Miek Gieben, книга на английском), в официальной документации по модулям чаще всего перечислены только методы,
Третья причина менее очевидна, чем предыдущая. Я называю «Go» языком «Си» с человеческим лицом, при это «Go» отстаёт от «Си» отсутствием предпроцессора. Когда я делал MakeCorner мне хотелось сделать кроссплатформенное определение количества процессоров (сейчас этот код удалён), для этого пришлось использовать вызовы, которые есть на одно системе, но отстутствуют на другой.
В «Go» это означает ошибку при компиляции. Нет никакого внутреннего средства для того, чтобы сообщить компилятору «не смотри сюда, если это freeBSD». Эту ситуацию мне пришлось разрешать при помощи файла make.
Нет худа без добра, вчера ночью я
Но. Это очень мешает и раздражает, особенно когда переходишь с такого динамического языка как «Пайтон». В больших проектах это должно вносить ужасную путаницу, так как придётся готовить несколько файлов для разных платформ (я так и сделал в своём проекте) и выделять куски кода в эти файлы
У меня уже есть задумка что писать на «Go» дальше. Правда я в сомнениях. «Go» настолько непопулярен, что выгоднее делать следующий проект
MakeCorner: теперь уголки мне нравятся
Программа, кстати, автоматически должна стать мультплатформенной. Я не пробовал, но компилятор Go есть для MacOS, FreeBSD, Linux и Windows (и трёх типов архитектур — ARM, i386
Правда, для работы требуется библиотека GD, а она вряд ли скомпилируется на ARM.