
#import <Foundation/Foundation.h>
int main()
parts := ['hello', 'world']
greeting := ''
for String part in parts
if part == parts[0]
Locale myLocale = Locale.currentLocale
greeting << part.capitalizedString
else
greeting << ' '
greeting << part
Log('%@', greeting + '!')
return 0
На днях из любопытства решил посмотреть, на какой стадии находится проект Eero — диалект Objective-C с альтернативным легким синтаксисом. Оказалось, что проделан уже большой фронт работ и Eero представляет из себя очень интересную разработку.
Пример кода
Для затравки традиционное сравнение небольшого участка кода на Eero и на Objective-C.
#import <Foundation/Foundation.h>
@interface FileHelper : NSObject
@property (readonly) NSString* name;
@property (readonly) NSString* format;
-(NSFileHandle*) openFile: (NSString*) path;
-(NSFileHandle*) openFile: (NSString*) path
withPermissions: (NSString*) permissions;
@end
@implementation FileHelper
-(NSString*) name {
return @"Macintosh";
}
-(NSString*) format {
return @"HFS+";
}
-(NSFileHandle*) openFile: (NSString*) path {
return [NSFileHandle fileHandleForReadingAtPath: path];
}
-(NSFileHandle*) openFile: (NSString*) path
withPermissions: (NSString*) permissions {
NSFileHandle* handle = nil;
if ([permissions isEqualTo: @"readonly"] || [permissions isEqualTo: @"r"]) {
handle = [NSFileHandle fileHandleForReadingAtPath: path];
} else if ([permissions isEqualTo: @"readwrite"] || [permissions isEqualTo: @"rw"]) {
handle = [NSFileHandle fileHandleForUpdatingAtPath: path];
}
return handle;
}
@end
#import <Foundation/Foundation.h>
interface FileHelper
String name {readonly}
String format {readonly}
openFile: String, [withPermissions: String], return FileHandle
end
implementation FileHelper
name, return String = 'Macintosh'
format, return String = 'HFS+'
openFile: String path, withPermissions: String = 'readonly', return FileHandle = nil
if permissions == 'readonly' or permissions == 'r'
return FileHandle.fileHandleForReadingAtPath: path
else if permissions == 'readwrite' or permissions == 'rw'
return FileHandle.fileHandleForUpdatingAtPath: path
end
Введение
Eero это полностью интерфейсно и бинарно совместимый диалект Objective-C. Реализован с помощью форка LLVM/clang компилятора, т.е. генерирует бинарный код напрямую, благодаря чему с ним работают стандартные инструменты разработки LLVM/Clang, включая отладчик, статический анализатор и прочие. Также заявлена экспериментальная конвертация Eero кода в стандартный Objective-C код 1.
В Eero можно напрямую использовать все Cocoa-фреймворки и любой Objective-C/C++ код, достаточно лишь подключить нужные заголовочные файлы. Также легок и обратный процесс: если для Eero-класса интерфейс определить на Objective-C, то его можно использовать напрямую, бинарные файлы полностью совместимы.

Синтаксис
Документация написана качественно и легко читается, для каждой особенности языка указывается мотивация, почему решили сделать именно так, в основном это: читаемость, безопасноть, DRY, WYSIWYG. Интересных деталей в языке много, я не буду рассматривать все, а ограничусь небольшим субъективным списком.

int count = 0
while ( count < 100 )
something = false
count++
i++; j++

id myarray = NSMutableArray.new
myarray.addObject: myobject
myarray.insertObject: myobject, atIndex: 0

NSString mystring = myobject.description
NSString otherString = (NSString) someObject

i := 100
mystring := myobject.description

mystring := String.stringWithUTF8String: "Hello, World"
Компилятор сначала проверяет имена сущностей в том виде, как они указаны в коде, и, если имя не найдено, добавляет зарегистрированные префиксы. Декларация дополнительных префиксов осуществляется с помощью директивы
using prefix
.using prefix AB
...
theAddressBook := AddressBook.sharedAddressBook
Однако в текущей реализации есть существенный недостаток: возникновение коллизий в результате опущения префиксов никак не отслеживается, просто используется первый подходящий вариант:
void AAPrint(String str)
NSLog('AA: %@', str);
void BBPrint(String str)
NSLog('BB: %@', str);
using prefix AA
using prefix BB
...
Print('test') // AA: test

initWithBytes: const void*,
length: UInteger,
encoding: StringEncoding
Тип возвращаемого значения указывается после аргументов, по умолчанию используется void.
initWithBytes: const void*,
length: UInteger,
encoding: StringEncoding,
return id
В Objective-C в случае, когда у метода есть опциональные параметры, принято определять несколько методов с разным количеством аргументов. В Eero можно декларировать методы с необязательными параметрами.
interface MyClass
openFile String, [withPermissions: String], return FileHandle
end
В имплементации дефолтное значение опционального аргумента обозначается с помощью знака "=".
implementation MyClass
openFile: String, withPermissions: String = 'r', return FileHandle
handle := nil
if permissions == 'r'
handle = FileHandle.fileHandleForReadingAtPath: file
else if permissions == 'w' or permissions == 'rw'
handle = FileHandle.fileHandleForUpdatingAtPath: file
return handle
end
Можно указать дефолтное возвращаемое значение, что например позволяет определять очень компактные геттеры:
implementation MyClass
model, return String = 'G35'
serialNumber, return String = 'X344434AABC'
end

interface MyClass
String name {nonatomic, copy}
String desc {readonly}
end

myblock := (int x, int y)
if x < 0
printf( "value was negative! (%d)\n", x )
x = 0
return x + y
Также поддерживается компактная форма записи для простых блоков, состоящих только из возвращаемого выражения:
xyblock := (int x, int y | return x + y)
descriptions := mylist.mapWith: (id element | return element.description)

mystring := MutableString.new
mystring.appendString: 'Hello, World'
if mystring == 'Hello, World'
// попадаем сюда, т.к. выражение выше истинно
При использовании бинарного оператора "+" сообщение stringByAppendingString будет послано всем объектам, которые могут на него ответить (преимущественно NSString и его субклассы):
helloString := 'Hello'
worldString := 'World'
helloWorldString := helloString + ', ' + worldString
Аналогично оператор "<<" посылает сообщение appendString:
mystring := ''
mystring << 'Hello, World'
Для своих классов можно перегружать следующие операторы:
Оператор | Селектор | Примечание |
+ | plus: | Включая оператор += |
- | minus: | Включая оператор -= |
* | multipliedBy: | Включая оператор *= |
/ | dividedBy: | Включая оператор /= |
% | modulo: | Включая оператор %= |
< | isLessThan: | |
<= | isLessThanOrEqualTo: | |
> | isGreaterThan: | |
>= | isGreaterThanOrEqualTo: | |
<< | shiftLeft: | |
>> | shiftRight: |

Ну, и наконец, в языке на уровне компилятора запрещен
goto
. :)Установка и использование
Данный раздел написан по опыту использования Eero в сборке 2013-12-08, XCode 5.0.2 и Mac OS X 10.8.5.
Ставится Eero очень просто. Достаточно скачать и установить плагин для XCode, который уже содержит сборку форка компилятора LLVM. При установке также добавятся шаблоны XCode для создания новых .eero и .eeh файлов. После установки достаточно перезапустить XCode и всё, — можно приступать к работе.
Работает подсветка синтаксиса, автодополнение. Однако, не работает выпадающий список с навигацией по классу, вместо него статичная надпись «No Selection».

Точнее говоря, XCode не видит классы и методы, определенные в файле, но можно воспользоваться инструкциями
#pragma mark ...
, — они в выпадающем списке видны.Проверил работу отладчика (он же debugger), всё в порядке. Однако, к сожалению XCode падал при попытке просмотра quick help к выделенному коду. Ещё не всегда корректно работают авто-отступы, но это совсем мелочь. Больше проблем не обнаружено.
Заключение
Лично на меня Eero произвел самое приятное впечатление. Да, язык достаточно молод (домен eerolanguage.org зарегистрирован в январе 2011, а на гитхабе проект появился в декабре того же года), и потому присутствуют недостатки, характерные для данной стадии развития (в основном с интеграцией с IDE). Однако, неразрешимих и критичных проблем не видно, а потому у меня появилось стойкое желание попробовать его в будущих проектах.
Ссылки
- Официальный сайт
- GitHub
- Блог и твиттер автора Andy Arvanitis
1) На данный момент функция конвертирования Eero -> Objective-C сыровата, у меня удачно отработала только на элементарных примерах.
Комментарии (63)
Krypt
16.12.2013 10:14Диспозиция:
@interface TestObject : NSObject { int test; } @property (nonatomic, assign, getter = getTest) int test; @end @implementation TestObject @synthesize test; - (id) init { if (self = [super init]) { NSLog(@"test %d %d", self->test, self.test); } return self; } - (int) getTest { NSLog(@"getter"); return 1; } @end
Вывод:
2013-12-16 13:17:24.637 Test[1224:907] getter
2013-12-16 13:17:24.815 Test[1224:907] test 0 1
Вопрос:
Как это повторить?
P.S.: Я знаю, что так делать не стоит, но раз вы предлагаете Eero как замену Objective-C — он так тоже должен уметь.Yan169 Автор
16.12.2013 10:14Примерно так:
interface TestObject int test {nonatomic} end implementation TestObject int _test init, return instancetype = self if (self = super.init) Log('test %d %d', _test, self.test); test, return int = 1 Log('getter'); end
Но по философии языка он должен выполнять те же функции, что Objective-C, но не являться его копией, взяв лучшее, и выкинув худшее. Поэтому далеко не все трюки можно перенести (особенно нежелательные в использовании). Например, в Eero запрещено затенять переменные (shadowed variables):
counter := 0 if isReady counter := 0 // compiler error
Krypt
16.12.2013 10:14Собственно в этом коже getter не нужен даже, надо только функцию в
- (int) test
переименовать.
> Например, в Eero запрещено затенять переменные (shadowed variables)
А можноо про это поподробне?
То есть я не смогу сделать так
BOOL status = NO; if (!status && <длинное условие>) status = YES; if (!status && <второе длинное условие>) status = YES; if (!status && <третье длинное условие>) status = YES;
?
Правда надо признать, более красивый код я придумать не смог :)
Навеяно вот этим кодом: pastebin.com/csQmX1BSalhimik45
16.12.2013 10:14Нет, это что-то типа (пример фигня, конечно):
BOOL status = NO; if(cond){ BOOL status = YES; ... }
Хотя иногда, например в лямбде, бывает удобно назвать переменную так же, как и снаружи, ибо другого нормального имени не придумаешь (пишу про CoffeeScript, меня там это пару раз доставало)Yan169 Автор
16.12.2013 10:14Да, иногда это бывает полезно. С другой стороны, защищает от потенциальных ошибок. Чисто субъективно, я бы предпочел вариант с warning, а не с compile error.
potan
16.12.2013 10:14У меня как раз наоборот — ошибки лезут когда приходится создавать новую переменную, а обращаюсь случайно к старой.
Правда это специфично для Haskell. Там нельзя написать
надо давать новое имяlet n = n+1 in ...
let n1 = n+1 in ...
В ML можно, в Haskell придумал замену
но уж больно многословно получается.case n+1 in n -> ...
Yan169 Автор
16.12.2013 10:14Нет, в вашем коде используется одна и та же переменная, так естественно можно писать. Запрещено в локальной области видимости определять новую переменную с тем же именем, что и в родительской. В Objective-С/C так делать можно (можно настроить, чтобы выдавался warning).
BOOL status = NO; if (...){ BOOL status = YES; }
rule
16.12.2013 10:14Забавно, как побаловаться.
Но пока шило на мыло помоему.
В любом случае многие очень сильные проекты начинались именно вот с такого вот рода экспериментов.
Triang3l
16.12.2013 10:14Какая-то хипстерота. Читать невозможно. Функции как списки переменных выглядят.
KysokZla
16.12.2013 10:14Вообще непонятно зачем? У всех языков свой синтаксис, странным он кажется только тем людям, которые его просто видят в первый раз, если человеку необходим этот язык он начнет его учить и через уже месяц не будет никаких проблем, а, возможно, он даже ему понравится намного больше чем остальные, тут есть множество своих плюсов, как и в любом другом языке. Давайте для Java создадим тоже свой Ero с блекджеком и щлюхами, я подозреваю, что для людей, программирующих на ассемблере или Pascale Java тоже кажется с очень странным синтаксисом.
Yan169 Автор
16.12.2013 10:14На вопрос «зачем?» автор отвечает: «для читаемости, т.к. код читается гораздо чаще, чем пишется».
Вообще, я согласен, что привыкаешь ко всему, Objective-C лично я воспринимаю абсолютно нормально, особенно после 5 лет разработки. :)
Но объективно говоря, код на Eero получается куда лаконичнее, плюс дополнительные функции, такие как опциональные аргументы, перегрузка операторов, полная поддержка instancetype, итераторы типаfor int i in 0 .. 10
и прочее. Т.е. дело не только в синтаксисе.Krypt
16.12.2013 10:14Ну если бы не другой синтаксис — возможно, я бы его даже попробовал. А так… Нет, я останусь на Obj-C :)
Yan169 Автор
16.12.2013 10:14Мне Objective-C нравится: философией, рантаймом. Но от синтаксиса я не в восторге, хотя и привык. По-моему, если подходить непредвзято, и забыть про привычки, то можно объективно сказать, что синтаксис Objective-C далек от совершенства: для тех же самых функций можно было придумать куда более удобную запись.
Krypt
16.12.2013 10:14Код Obj-C, раза в 1.5-2 длиннее по сравнению с тем же C#, это да. Но по сравнению с C++ я выигрыша не вижу. Причём если в Obj-C однозначно, то в случае с С++ — кто как хочет, тот так и городит. Так что я бы на синтаксис Obj-C не особо жаловался :)
potan
16.12.2013 10:14И у этого языка свой синтаксис, при обеспечении совместимости по библиотекам. Что плохого то?
artyfarty
16.12.2013 10:14Нам не нравится непонятный синтаксис обжСи, поэтому мы сделали свой непонятный синтаксис! Теперь непонятных синтаксисов два.
При всем моём неприятии синтаксиса обж си,
name, return String = 'Macintosh' format, return String = 'HFS+'
в оригинале куда понятнее. И что за мода вообще, делать эти руби/питон стайл диалекты языкам…
Goodkat
16.12.2013 10:14Лучше бы они старый добрый и всем понятный C++-синтаксис для Obj-C сделали, если хотели избавиться от вложенных квадратных скобок при обращении к методам.
А Python-стиль для C — это как-тонеправильносовсем запутывает, имхо.Yan169 Автор
16.12.2013 10:14В C++ нет именованных параметров, поэтому его синтаксис никак не применить.
Goodkat
16.12.2013 10:14Это даже не именованные параметры, а имя метода состоящее из нескольких слов перемежающихся параметрами.
Прелесть именованных параметров в том, что их можно писать в произвольном порядке.Zelgadis
16.12.2013 10:14Так сигнатуры методов это же божественная часть Objective C! Не понимаю людей которым ObjC не нравится.
PapaBubaDiop
16.12.2013 10:14Хотя мое мнение никого не интересует, но скажу
Мне очень нравятся квадратные скобки
Они напоминают сказочный сюжет про сундук. В сундуке — медведь. В медведе — утка. В утке яйцо. В яйце — игла. На конце иглы — смерть.
int death = [NSBox boxWithBear:[NSBear bearWithDuck:[NSDuck duckWithEggs:[NSEgg eggWithNiddle:[NSNiddle alloc] init]]]];
Agent_Smith
16.12.2013 10:14Да, так намного лучше:
int death = NSBox.boxWithBear(NSBear.bearWithDuck(NSDuck.duckWithEggs(NSEgg.eggWithNiddle(new NSNiddle))));
Goodkat
16.12.2013 10:14[NSNiddle niddleWithADeath:[[NSDeath alloc] init] atTheEnd:theEnd]
PapaBubaDiop
16.12.2013 10:14Ваш пример лучше. В моем умышленная ошибка, никто не поправил.
Goodkat
16.12.2013 10:14Собственно, я не поправил, а расширил создание объекта иглы — остальное было лень набирать.
А у вас да, ошибка, в death будет не смерть, а сундук :)Yan169 Автор
16.12.2013 10:14Ошибка в части
[NSEgg eggWithNiddle:[NSNiddle alloc] init]
Никто не поправил очевидно потому, что в скобочках таки легко запутаться. :)Krypt
16.12.2013 10:14Зачем замарачиваться скобками, если их компилятор проверит ;)
Yan169 Автор
16.12.2013 10:14Чтобы не было ситуации «чукча не читатель, чукча писатель». Код читается намного чаще, чем пишется.
Кроме того, компилятор не всесилен. Предположим, мы решили понизить связанность классов и сделать их более универсальными, так, чтобы в одной сущности могло находиться по 2 других:
@protocol NSContaining <NSObject> -(instancetype)initWith:(id)content; -(instancetype)initWith:(id)content and:(id)anotherContent; @end @interface NSBear : NSObject <NSContaining> @end @interface NSDuck : NSObject <NSContaining> @end @interface NSEgg : NSObject <NSContaining> @end
Слабо сходу понять, чем отличаются следующие синтаксически верные варианты:
[[NSBear alloc] initWith:[[NSDuck alloc] initWith:[[NSEgg alloc] initWith:[[NSNeedle alloc] init]]] and:[[NSEgg alloc] init]]; [[NSBear alloc] initWith:[[NSDuck alloc] initWith:[[NSEgg alloc] initWith:[[NSNeedle alloc] init]] and:[[NSEgg alloc] init]]]; [[NSBear alloc] initWith:[[NSDuck alloc] initWith:[[NSEgg alloc] initWith:[[NSNeedle alloc] init] and:[[NSEgg alloc] init]]]];
Если просто убрать лишние скобки, оставаясь в рамках Objective-C, и воспользоваться нотацией через точку, то уже намного понятнее:
[NSBear.alloc initWith:[NSDuck.alloc initWith:[NSEgg.alloc initWith:NSNeedle.alloc.init]] and:NSEgg.alloc.init]; [NSBear.alloc initWith:[NSDuck.alloc initWith:[NSEgg.alloc initWith:NSNeedle.alloc.init] and:NSEgg.alloc.init]]; [NSBear.alloc initWith:[NSDuck.alloc initWith:[NSEgg.alloc initWith:NSNeedle.alloc.init and:NSEgg.alloc.init]]];
На практике «скобочный ад» тоже иногда бывает, например при использовании fluent-интерфейсов, при использовании ReactiveCocoa. Т.е. не «ад», конечно, но «ещё чуть-чуть, и будет ад».
В общем, Readability matters!Krypt
16.12.2013 10:14За такой код руки отрывать надо.
Во-первых, можно сразу бить в табло за кривые имена параметров. Ибо правильноinitWithDuck:(NSDuck*)duck
Во-вторых, бить по пальцам за отсутствие форматирования.
Сравните:
NSBear *bear = [[NSBear alloc] initWithDuck:[[NSDuck alloc] initWithEgg:[[NSEgg alloc] initWithNeedle:[[NSNeedle alloc] init]]] egg:[[NSEgg alloc] init]]; NSBear *bear = [[NSBear alloc] initWithDuck:[[NSDuck alloc] initWithEgg:[[NSEgg alloc] initWithNeedle:[[NSNeedle alloc] init]] secondEgg:[[NSEgg alloc] init]]]; NSBear *bear = [[NSBear alloc] initWithDuck:[[NSDuck alloc] initWithEgg:[[NSEgg alloc] initWithNeedle:[[NSNeedle alloc] init] egg:[[NSEgg alloc] init]]]];
В-третьих, стоило бы тут вынести агрументы ав отдельные переменные
В-четвёрных, от этого кода пахнет архитектурной… попой.
P.S.: форматеры хабра и pastebin'а пытаются выравнять код по 80 символов, что в реалях Obj-C — идиотское занятие. Скопируйте в XCode, и смотрите там.Krypt
16.12.2013 10:14Кстати, код всё равно кривой. Если нет ARC — будет течь память. Ибо, по конвенции, функции, init* и copy возвращают значение с retainCount = 1. Объексты с retainCount = 0 возвращают функции вида [NSNeedle needle].
Yan169 Автор
16.12.2013 10:14Объекты с «retainCount = 0» никакие методы не возвращают. См. autorelease и NSAutoReleasePool.
Yan169 Автор
16.12.2013 10:14Нет. Если уж Вы решили вспомнить manual reference counting (хотя это абсолютно не к месту), то конвенцию надо приводить полностью и правильно (“alloc”, “new”, “copy”, “mutableCopy”, никакого
«init»!), и не писать очевидную чушь. Вас могут читать новички в Objective-C.
Krypt
16.12.2013 10:14Не придерайтесь, это к вопросу читабельности кода не относится.
А новичкам — брысь читать эту статью: Advanced Memory Management Programming Guide
P.S.: Оригинально вы выражаете несогласие в споре. Думаю, в таком случа, нет смысла его продолжать.
notxcain
16.12.2013 10:14Вам бы самим почитать еще раз. Предыдущий ответ вы написали на автомате, значит не до конца поняли.
Yan169 Автор
16.12.2013 10:14Ясно, что обсуждаем абстрактный пример в вакууме. И в равных условиях (что есть форматирование, что нет — вариант с меньшим количеством скобок читабельнее).
А ваш вариант не по теме, я же условие поставил: классы — универсальные контейнеры, реализующие протокол NSContaining (имена селекторов специально сократил, чтоб не так широко было). Или вы универсальные протоколы не используете, и классы у вас всегда жестко связаны?Krypt
16.12.2013 10:14Гм, зря сократили. Вводит в заблуждение.
В любом случае, последние 3 пункта не отменяются.
> Или вы универсальные протоколы не используете, и классы у вас всегда жестко связаны?
Практически не использую, кстати. Для хранения данных намного лучше подходят классы с конкретными именами и конкретными типами полей.
По поводу универсальных контейнеров у меня для есть отличный комментарий: govnokod.ru/12170#comment161695Yan169 Автор
16.12.2013 10:14Практически не использую, кстати.
Жесткая связанность классов — наше всё?
Если строим иерархию, например, сотрудников, то вместо универсального протокола {начальник; подчиненные} сотрудники будут выглядеть так:
ДиректорВасильев {ЗаместительКрючков; ЗаместительСвязнов} ЗаместительКрючков {ДиректорВасильев; НачальникОтделаКадровПучков; НачальникОтделаФинансовТранжиров} ...
Каждой сущности — свой класс. Очевидно нелепо, но именно так выглядит ваша поправка с Медведем, Уткой и Яйцами. Чтобы Утку заменить на Курицу, придется менять класс Медведя.
Agent_Smith
16.12.2013 10:14Отсутствие скобочек, куча сахара, итераторы, дефолтные значения параметров это круто очень. Но синтаксис просто жесть, все вывернуто через зад, не понятно зачем. Лучше бы они пошли по пути RubyMotion и MonoTouch, где куча сахара и плюшек из оригинальных языков, и при этом все легко читается, и порог входа сильно ниже.
Yan169 Автор
16.12.2013 10:14Objective-C:
[obj makeBoxWithOrigin: origin andSize: size];
Ruby Motion:
obj.makeBoxWithOrigin(origin, andSize: size)
Eero:
obj.makeBoxWithOrigin: origin, andSize: size
По-моему, явных преимуществ у Ruby нет.
Зато в Eero есть плюсы: это тот же Objective-C со статической типизацией, категориями, расширениями классов и пр. Ruby же изначально не писался под runtime Objective-C, и могут возникать сложности в самых простых местах (пример отсюда):
Objective-C@interface CustomView : UIView @property (copy) NSString *text; @end @implementation CustomView - (id) initWithFrame:(CGRect)frame { [super initWithFrame:frame]; self.text = @""; return self; } - (id) initWithText:(NSString*)text { UIFont *font = [UIFont systemFontOfSize:12]; CGRect size = [text sizeWithFont:font]; // skip local initializer [super initWithFrame:{{0, 0}, size}]; self.text = text; return self; } @end
Ruby Motionclass CustomView < UIView alias :'super_initWithFrame:' :'initWithFrame:' def initWithFrame(frame) super.tap do @text = '' end end def initWithText(text) font = UIFont.systemFontOfSize(12) size = text.sizeWithFont(font) super_initWithFrame([[0, 0], size]).tap do @text = text end end end
Eerointerface CustomView : UIView String text {copy} end implementation CustomView initWithFrame:CGRect, return instancetype = self if (self = super.initWithFrame: frame) self.text = '' initWithText:String, return instancetype = self font := UIFont.systemFontOfSize: 12 size := text.sizeWithFont: font CGRect rect = {{0, 0}, size} if (self = super.initWithFrame:rect) self.text = '' end
Это конечно не отменяет того, что в Ruby Motion много своих плюсов.
В Mono Touch же вообще нужно биндинг для использования Objective-C кода писать, насколько я знаю.
Triang3l
16.12.2013 10:14Чем обосновываете удаление goto?
EndUser
16.12.2013 10:14Andy Arvanitis просто hater — goto это не управляющая команда, а способ мышления.
Даже убрав эту команду, Andy Arvanitis продолжает ваять if return else return.
Уверен, он и break оставил.
Поэтому считаю, что удаление goto не обосновано ни разу, кроме как капризностью.corristo
16.12.2013 10:14А Вы давно goto видели где-то за пределами чистого Си? В каком-нибудь ядре Linux оно нужно и оправдано, зачем оно в более высокоуровневом языке?
Triang3l
16.12.2013 10:14Ну лично я сам использую в C++.
... m_pLockedData = new unsigned char[memoryRequired]; ComputeVertexDescription(m_pLockedData + m_FirstUnwrittenOffset); desc.m_nFirstVertex = 0; desc.m_nOffset = m_FirstUnwrittenOffset; return true; fail: ComputeVertexDescription(NULL, 0, desc); desc.m_nFirstVertex = 0; desc.m_nOffset = 0; return false;
... return handle; fail_plink: glDeleteProgram(program); fail_pcreate: glDeleteShader(pixelShader); fail_ps: glDeleteShader(vertexShader); fail_init: return SHADER_PROGRAM_HANDLE_INVALID;
ilammy
16.12.2013 10:14А можно было сделать на RAII без goto. В простых случаях это несколько длиннее, но зато более понятно и устойчиво. Это что касается освобождения ресурсов и обработки ошибок. Альтернатив goto для вложенных циклов я не вижу (выделить в функцию и сделать return — то же, только в профиль).
deleted-lucky_brick
16.12.2013 10:14фуу.
так же убого как coffee script
скобки это круто знает каждый лиспер.
во что круто =)
common-lisp.net/projects/cl-objc/cl-objc.pdf
pravic
16.12.2013 10:14Начали за здравие, а закончили за упокой. Убрали квадратные скобки — круто, но зачем отступы в стиле питон?
openFile String, [withPermissions: String], return FileHandle
Плохо читать оторванные друг от друга токены. Лучше бы сделали привычный стиль:
FileHandle openFile(String, [withPermissions: String])
handle = FileHandle.fileHandleForReadingAtPath(file)
Yan169 Автор
16.12.2013 10:14Такой синтаксис для Objective-C неоднозначен.
Представьте следующий интерфейс:
typedef id(^FileHandleFactoryBlock)(NSString *); @interface FileHandle : NSObject +(instancetype)fileHandleForReadingAtPath:(NSString *)path; +(FileHandleFactoryBlock)fileHandleForReadingAtPath; @end
Что произойдёт в результате вызоваFileHandle.fileHandleForReadingAtPath(file)
? Будут отослано сообщение fileHandleForReadingAtPath: с одним аргументом или fileHandleForReadingAtPath без аргументов с последующим вызовом полученного блока?
Я понимаю, что пример надуманный. Но если синтаксис создаётся специально под Objective-C рантайм, он определенно должен быть однозначен.
corristo
16.12.2013 10:14Не смотря на спорный синтаксис, первый убегу программировать на этом языке, если сделают parametrized types
Yan169 Автор
16.12.2013 10:14Я не стал раздувать статью, но в Eero поддерживается instancetype не только для возвращаемых значений, но и для аргументов.
Это позволяет делать что-то типа типизированных функторов. Упрощенный пример для типизированных коллекций:
stringArray := (String<MutableArray>)MutableArray.new stringArray.addObject: '123' stringArray.addObject: @13 // Warning: incompatible pointer type numArray := (Number<MutableArray>)MutableArray.new numArray.addObject: @13 numArray.addObject: 'ABC' // Warning: incompatible pointer type
(Класс MutableArray должен быть прокси, перенаправляющий сообщения из интерфейсов NSString/NSNumber всем элементам коллекции)
Не полноценные parametrized types конечно, но всё же.
Подробнее про instancetype: nshipster.com/instancetype/
Про типизированные коллекции в Objective-C: www.jonmsterling.com/posts/2012-02-05-typed-collections-with-self-types-in-objective-c.html
Makito
Увидев ":=" я сразу вспомнил Pascal и Delphi… Эххх были времена… :)
Xlab
А теперь ещё и в Go.