Pull to refresh

Comments 27

ИМХО, для ООП достаточно понятия object identity, и полиморфизма поведения (т.е. какой-либо механизм, при котором данный вызов может обрабатываться по-разному в зависимости от типа объекта). Т.е. например Go — несомненно объектно-ориентирован. Равно как и JS. И даже Lua.

Что касается цитаты Алана Кэя… может, он и придумал термин «ООП», но Simula, которая по факту уже была вполне себе ООП, появилась за несколько лет до Smalltalk. А объектная модель плюсов, это дальнейшее развитие Simula (в т.ч. и синтаксис — «virtual» родом именно оттуда). Так что не думаю, что у Кэя есть монополия на это дело.
Насколько я помню, в Simula 67 слово virtual означало лишь возможность перегрузки метода в наследниках, но полиморфизма не было: при вызове нужно было явно указать, метод какого именно класса использовать в данный момент. Сейчас не имею возможности перепроверить, но если так, то, следуя вашему же определению (и я с ним согласен), Simula по факту не был объектным. Так что монополия Алана Кэя сохраняется :)
«Частичный» пруфлинк: The Birth of Object Orientation: the Simula Languages by Ole-Johan Dahl. Автор называет механизм виртуальных вызовов «полудинамическим». Объяснение довольно туманное. Раньше где-то видел более наглядный пример (где явно показывалась необходимость точно указывать правильный класс объекта для правильного вызова виртуального метода), но сейчас не могу найти :(
В Википедии есть конкретный пример про virtual, где он используется ровно так, как в C++. Но вообще, конечно, это надо смотреть в спеке. Но там не текст, а отсканированные картинки, плюс терминология очень запутанная, так что я пока так и не смог разобраться.

Если судить по этой книге (по которой я, собственно, в свое время и изучал Симулу), необходимость указывать класс объекта через QUA — это не связанное с виртуальными функциями ограничение оператора точка, которое обходится использованием INSPECT.
Поигрался с Cim — там честные виртуальные вызовы, т.е. например:

begin
    class Base;
    virtual:
        procedure Foo is
            procedure Foo;
        ;
    begin
        procedure Foo;
        begin
            outtext("Base");
        end;
    end;

    Base class Derived;
    begin
        procedure Foo;
        begin
            outtext("Derived");
        end;
    end;

    ref(Base) obj;
    obj :- new Base;
    obj.Foo;
    obj :- new Derived;
    obj.Foo;
end


Печатает «Base Derived». Судя по этому, такое поведение ожидается.
Тоже мне, открыли секрет полишинеля. Объекты на Си так же делаются ;D
Я программирую и на Си и на Гоу, Си в отношении объектов до Гоу далековато.
Спасибо за перевод. Лично мне бы хотелось видеть больше о «Го» на хабре. Особенно что-то типа «Подборка интересностей за последнюю неделю»)
А была демо-подборка от человека, кто этим занимается: habrahabr.ru/post/221061/
Он написал, что остальные подборки будут на отдельном сайте, увы.
4gophers.com/ Там переодически появляются статьи «тулзовины и хреновины #X», там уже 7 таких статей, и я для себя нашел очень много интересного, редко конечно, но полезного очень много. Можете пройтись по всем статьям, найдете для начала информации на очень долгий период.
спасибо за ссылку. от себя могу добавить рассылку «go weekly».
Go по своему прекрасен, но есть очень спорный момент, обработка ошибок…
Ну, ошибки обрабатывать надо, так что сколько ошибок — столько и обработчиков. Во многих других языках можно плевать на них, вы можете плевать и здесь, но так дела не делаются. Наилучший вариант — пробрасывать ошибки снизу вверх через return err, как можно выше. А что кроме этого вас не устраивает?
А что не так с обработчиком ошибок?
Опишите кейс, который вызвал трудности. Не считаю себя go-гуру, но пара демонов в продакшне имеется, последний достаточно жирный по коду.
с обработчиком ошибок все так

иногда глаза рябит от количества err которые нужно проверить в коде

	if err != nil {
		log.Fatal(err)
	}
	//или такого
	if err != nil {
		return nil, err
	}

привычнее конструкция
try{

}catch

но как говорится все это дело привычки
Попробуйте использовать механизм panic — recover. Практически тот-же try — catch, только привязанный к границам функций.
В Go panic это для непредвиденных разработчиком исключительных ситуаций, которых просто не должно быть, типа обращения к null. Если мешать его с механизмом предвиденных исключительных ситуаций (error), получится хрень.
У нас на первом курсе люди в C# оборачивали Main в try-catch и были довольны стабильностью, но так дела не делаются. В любом случае, при правильном подходе будет рябить либо от проверок err, либо от проверок try-catch.
Так точно делать не нужно.
Вы можете написать что-то типа:
Control.try(func(){
    // code
    _, err := my.func(); Control.handle(err);
    // code
}).cath(func(message err){
    // handle
})


Но во-первых это будет дорого. Во-вторых породит кучу геммороя. В-третьих будет совсем не Go-way и с вашим кодом никто работать не будет.
Парадигму Go в отношении ошибок обрабатывайте и работайте, вашу мать, с ошибками там, где они происодят нужно либо принять, либо забыть про язык.

Паника нужна тогда, когда действительно паника. Мы не можем дальше работать, мы не знаем, что делать — всё пропало.
Всем надо пользоваться с умом. Есть соглашение, об этом написано в статье Effective Go — Errors, что сигнатуры библиотечных методов и функций должны соответствовать определенному формату, а именно, возвращать error, если может иметь место исключительная ситуация. Но внутри кода своей библиотеки вы можете использовать и механизм panic — recover, когда это оправдано (даже для обработки предвиденных ошибок).
Например есть цепочка вызовов функций и исключительная ситуация может возникать где-нибудь на глубине пятого уровня. Чтобы не пробрасывать вручную и не писать в каждой функции проверки типа if err {return err}, уместно использовать panic и просто отловить проброшенное исключение на верхнем уровне. Почему это будет дорого? Ведь .NET и Java используют именно такую модель обработки ошибок. А каком геморрое вы говорите? И почему это будет не Go-way? Ведь если существуют подобные механизмы языка, значит ими можно пользоваться, но и это не значит что их следует пихать везде, где вздумается. Более того, такой способ используют сами разработчики, например в пакете regexp, вот здесь кратко описано что, где и зачем: Effective Go — Recover
Никто не утверждал, что в особых ситуациях глубоко внутри пакета НЕЛЬЗЯ сделать panic и затем где-нибудь вверху его поймать. Конечно же можно, только вот ловля ошибок с этим никак не связана. Попробуйте создать папку и файл, записать в файл текст — вы должны отловить 4 возможные ошибки, что заставит скопипастить любой код ловли ошибок, каким бы он не был.
Почему это будет дорого?
Товарищ привёл пример кода и о нём говорил, что дорого и муторно.

А что касается предназначения panic, об этом явно написано в том же Effective Go:
But what if the error is unrecoverable? Sometimes the program simply cannot continue.
This is only an example but real library functions should avoid panic. If the problem can be masked or worked around, it's always better to let things continue to run rather than taking down the whole program.
Почему это будет дорого? Ведь .NET и Java используют именно такую модель обработки ошибок.

Go не JAVA и не .NET. Предполагается, что модель Go в области обработки ошибок это эволюция. Есть механизм panic, есть механизм Error.
Исключения в Go не нужны. И нужно очень извратить свой мозг, чтобы они появились(типа той реализации, что я привел).

О каком геморрое вы говорите?

Есть такая ситуация, которая ведет к боли обычно — попытка перенести привычный опыт на всё новое. Go не про огромные системы с DI, не про абстрактные классы и кучи фабрик. Он про решения больших задач маленькими пакетами. Во-всяком случае я в этом уверен.
И маленькие пакеты при вызове своих функций могут вернуть ошибку.

И почему это будет не Go-way?

Вы можете посмотреть на случаи использования panic в стандартной библиотеке.

У меня на работе демон с 30k строк только моего кода крутится, написанный на Go и я не испытал трудностей или проблем с обработкой ошибок. Паника используется тогда, когда мы не можем дальше продолжать работать и это правильно.
Я бы вообще порекомендовал попридежать panic на время первичного знакомства с языком.

По-поводу дорого — я думаю написать статью на недельке по-поводу ошибок, почему они именно так сделаны и про panic-recovery тоже. С бенчмарками. И примерами из стандартной библиотеки.

Возможно, я немного резок, но это потому, что не хочется, чтобы перековали приятный и умный язык на какую-нибудь JAVA.
По-поводу return val,val,val могу посоветовать только использовать именованные возвращаемые параметры.
Не забывайте только о разнице между := и =, хотя по-моему новые версии компиляторов уже сообщают о ошибках типа %var% is shadowed during return

Или можно так:

func foo() (err error) {
	var v bool
	if v1, err = baz(); err == nil {
		if v, err = bar(); err == nil {
			println("value is", v, v1)
		}
	}
	return
}


Правда мне кажется, что такие кульбиты выглядят похуже проверки возвращаемого err на nil.

UFO just landed and posted this here
Вообще концепт анонимных полей используется для встраивания структур и с си-подобными языками это никак не связано. Здесь походу требуется некоторое понимание концептов Go.
Другое дело, что при использовании встраивания мы добиваемся того, что напоминает си-подобное наследование, но не более. Об этом и есть статья, кстати.

«удалил его имя, а про тип забыл» — ну знаете ли, в программе можно много чего удалить, а чего-то забыть, лучше от этого никому не станет ни на каком-либо другом языке. И нет ничего плохого, если класс вдруг станет наследником, это же не полноценное наследование, он просто приобретёт новые свойства/методы и всё.

«но не превратиться ли код на нем через пару лет в спагетти» — любой код превратится в хрень, если забывать что-то там удалять. Другое дело, что подходы Go меньше всего способствуют образованию хренового кода, я бы сказал даже препятствуют.
Вы можете быть не знакомы со Simula, но, вне всяких сомнений, точно знаете некоторые из тех языков, для которых он стал вдохновением — Java, C++, C# и Smalltalk, которые позже, в свою очередь, сильно повлияли на Objective-C, Python, Ruby, Javascript, Scala, PHP, Perl… полный перечень содержит почти все популярные современные языки.

Перечень языков для которых он встал вдохновением — крайне странен. Откуда в списке взялись Java ('95), C# ('00)? Уж явно не у Simula черпалось вдохновение, т.к. череда событий перед между '67 и '95 уж точно была не маленькая. А дальше вообще смешно, «позже» и «сильно повлияли на» — Obj-C ('83, рядом с C++, кстати), Perl ('87), Python ('91). Даже если «повлияли» имелось в виду на развитие в процессе, то, опять же, ну уж никак не Simul'ой в головы поэтичных япошек и минималистичных американцев приходили их идеи. Клевая статья, но этот абзац просто выбил из колеи, честное слово.
Симула впервые появилась в 67-м, но она тоже развивалась и стандартизировалась. Последняя спецификация датирована 86-м.

Но, да, список все равно странноватый. C# там точно не к месту — это дитя Java и Delphi.

Реально Симула была прямым вдохновлением для C++, причем это вполне достоверно — помимо вполне очевидных синтаксических заимствований, Бьёрн об этом говорил открыто уже много раз, и в C++ FAQ есть соответствующий пункт.

Насколько она был прямым вдохновением для Java, я не знаю, но факт то, что объектная модель последней намного ближе к оригинальной симуловской (классы исключительно как reference-типы, одиночное наследование), чем плюсовая. А Гослинг в свое время работал над одним из популярных компиляторов Симулы, и высказался по этому поводу так: «Simula pushed my love for object oriented programming. Simula was pure and simple. It was really a lovely language to use». И вроде бы как-то раз на JavaOne он обмолвился, что она оказала сильное влияние на дизайн языка.

Про «повлияли» — видимо, имелось в виду, что повлияли C++/C#/Smalltalk/Java, причем в каждом конкретном случае имеют смысл только некоторые комбинации — т.е., например, Obj-C явный наследник Smalltalk.
Sign up to leave a comment.

Articles