avva: (Default)
[personal profile] avva

Это будет интересно только программистам.

Мне пришло в голову пару дней назад, что нет собственно причины, по которой в Джаве должно быть ключевое слово implements. Наверное, это тривиальная мысль, но мне до сих пор не приходила в голову.

Предположим, у нас есть интерфейс Foo и класс Bar. Предположим, в классе есть определения всех методов, которые перечислены в интерфейсе, с правильными аргументами, типами возврата и другими атрибутами. Значит, компилятор может этот факт в любой момент проверить напрямую, сверив определения класса и интерфейса (причем класс может быть в скомпилированной форме). В любом месте, где мы хотим использовать объект класса Bar (или его подкласса), а ожидают интерфейс Foo - например, в списке аргументов какого-то метода - сейчас компилятор проверяет правильность подстановки, основываясь на том, что в определении Bar написано "implements Foo". Но если бы не было написано, он все равно мог бы проверить правильность подстановки, просто напрямую сравнив типы методов класса и интерфейса.

(Я что-то упускаю тут или правильно все описал?)

Если это ключевое слово не нужно, зачем же оно есть? Зачем дизайнеры языка заставляют программиста специально написать, что класс Bar воплощает интерфейс Foo, если это не дает компилятору новой информации? Я бы сказал - по двум причинам; во-первых, из идеологических соображений, чтобы заставить программиста иметь в голове стройную картинку того, кто что воплощает. Во-вторых, чтобы была дополнительная проверка совместимости класса с интерфейсом в момент определения класса, а не только в момент его использования в качестве интерфейса. Без этой проверки, скажем, ошибка в определении класса, делающая его несовместимым с интерфейсом, обнаружилась бы только в момент использования класса там, где требуется интерфейс, а не во время компиляции самого класса с интерфейсом.

Что было бы лучше, если бы не было слова implements? Предположим, у меня есть некий достаточно простой интерфейс с одним-двумя методами, воплощающий некую идею; и класс, который написал не я и контролирую не я (возможно, только в скомпилированном виде), который воплощает эту идею, с ровно теми же именами методов и типами, но его создатели ничего не знали про мой интерфейс. Сейчас, чтобы их состыковать, мне надо делать дополнительный класс посредине, который прячет в себе объект настоящего класса и делегирует ему все, что нужно. Если бы компилятор не опирался на implements, а проверял настоящие типы, мне бы это не нужно было делать. Оно бы просто работало само по себе.

См. также интересную статью JavaGI: Generalized Interfaces for Java, которая натолкнула меня на эту нехитрую мысль. JavaGI - интересная попытка внести в Джаву идею type classes из Haskell. Предположим, у вас есть интерфейс и класс, скорее всего из разных источников (возможно, только в скомпилированном виде), причем класс как бы воплощает все, что нужно интерфейсу, но не под теми же именами, и возможно с некоторыми тривиальными изменениями. Обычное решение, опять-таки - промежуточный класс, Adapter pattern. Вместо этого предлагается новый синтаксис, который совмещает класс и интерфейс вместе, "объясняя" компилятору, как воплотить методы интерфейса в терминах методов класса, так, что после этого компилятор может подставлять объект класса туда, где нужен интерфейс, как обычно. Нет умножения сущностей в виде ненужного по сути дела промежуточного класса; вместе с тем сохраняются все проверки типизации, обычные для Джавы. Довольно любопытная идея.

Date: 2007-01-04 11:46 am (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
Охосспади, ну можно тогда динамически протагить все классы как только стал известен этот новый интерфейс. Однократная же операция (в смысле, над классами, а не над объектами)!

Не, технически ничего в этом страшного нет, как и в рефлекшене, впрочем.

Date: 2007-01-04 11:55 am (UTC)
From: [identity profile] 109.livejournal.com
define "страшного". и, while you are at it, запусти два раза в цикле метод, который делает i++ - один раз так, а другой раз через reflection. во сколько раз медленнее стало?

Date: 2007-01-04 01:05 pm (UTC)
From: [identity profile] 109.livejournal.com
в смысле processor cache? хорошо, можно придумать другой пример, и всё равно разница будет большая.

Date: 2007-01-04 12:47 pm (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
"страшного" == становящегося неустранимым боттлнеком.

Демагогия. Ещё раз повторяю: связывание происходит один раз, при подключении нового модуля, а не в цикле.

Жаловаться на тормознутость рефлекшена - это в точности то же самое, что жаловаться на необходимость парсить SQL (причём два раза! Один раз парсит движок БД, второй раз - приложение парсит результаты). Ах, столько времени уходит, ужас!

Запустил, кстати. Всего ~60 в раз тормознее (если поставить безрефлекшный код в те же условия -- необходимость тайпкастить) Дать код? Ужасно, конечно.

Date: 2007-01-04 01:13 pm (UTC)
From: [identity profile] 109.livejournal.com
во-первых, результаты парсить - это не sql парсить. где там два раза? во-вторых, не уловил аналогии. в-третьих, в 60 раз? господа присяжные, у меня вопросов больше нет. я ожидал что-то типа "в три раза" и это было бы совершенно неприемлемо для, например, проекта, который я делал полтора года назад.

Date: 2007-01-04 01:49 pm (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
> не уловил аналогии
Аналогия очень простая: оверхед, получающийся из-за того, что запросы и результаты гоняются между приложением и драйвером БД в текстовом виде, никого не волнует: основное время тратится вовсе не там.

Совершенно аналогично: ну да, у вас на, собственно, вызов метода по имени у какого-то левого объекта уйдёт не, скажем, 10 наносекунд, а целая микросекунда. При этом сам метод будет работать десятки миллисекунд.

А так да, перемножение матриц через рефлекшен лучше не писать =)

Date: 2007-01-05 02:47 am (UTC)
From: [identity profile] 109.livejournal.com
так вы признаёте, что аввино предложение увеличивает оверхед на вызов в десятки раз, или нет?

то, что "метод будет работать десятки миллисекунд" - демагогия чистой воды. от метода зависит, сколько он будет работать. всё, что мы можем сказать - что оверхед катастрофически увеличивается.

Date: 2007-01-05 12:01 pm (UTC)
From: [identity profile] faceted-jacinth.livejournal.com
Конкретно аввино предложение -- нет, потому что связывание выполняется один раз.

А за оверхед -- хотите я Вам страшную тайну открою: многие языки, например, ПХП, вообще интерпретируемые. И ничего, работают.

January 2026

S M T W T F S
    1 2 3
4 5 6 7 8 910
11 12 1314151617
18192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 14th, 2026 05:17 pm
Powered by Dreamwidth Studios