LINUX.ORG.RU

Что происходит с популярностью Go?

 ,


3

2

Примерно с лета прошлого года популярность языка программирования Go неуклонно падает. По крайней мере если верить индексам TIOBE и PYPL. В начале прошлого года Go входил в первую десятку самых популярных языков программирования, но сейчас он уже во второй десятке - ближе к её нижней границе. Если TIOBE и PYPL не отражают действительность, то какие другие индексы отражают её лучше? Хотя на https://langpop.com/ Go всё ещё в первой десятке. Что вообще происходит с Go и каковы ваши прогнозы на ближайшие пару лет?

Ну и чтобы два раза не вставать, дополнительный вопрос. Один из конкурентов Go - это JavaScript/TypeScript на платформе node.js. Когда популярность Go росла, значительный процент новых программистов на Go был представлен теми, кто переходил на него с JS/TS. Однако если сейчас посмотреть на объявления о работе (живу не в России), то там какое-то засилие именно JS/TS, причём в основном это молодые компании и стартапы. Можно ли это объяснить банальной экономией на найме, когда одни и те же люди делают и бэкэнд и фронтэнд? Иначе я никак не могу понять тягу к языку, в котором нет нормальной параллельности и вообще куча костылей и легаси.

Update: большой брат подслушал и порекомендовал в ютубе: www.youtube.com/shorts/Vh97uPhmhqI



Последнее исправление: hummer (всего исправлений: 2)
Ответ на: комментарий от kaldeon

Современное определение ООП таково: инкапсуляция, наследование, полиморфизм, абстракция.

Но это не "современное определение ООП", это какой-то бессвязный бред из часто встречающихся умных слов.

Современное определение ООП выглядит точно так же, как оно выглядело в момент своего создания 40 лет назад:

Object-oriented programming (OOP) is a programming paradigm based on objects … An OOP computer program consists of objects that interact with one another.

Проблема в том, что при наследовании нет чёткой границы между контрактом и деталями реализации.

Нет такой проблемы. Есть проблема людей в программировании, которую сейчас пытаются решить внедрением ИИ. Проблема сводится к тому, что некоторые из людей не понимают концепций инвариантов, обеспечивающих эти инварианты инкапсуляции, и публичных интерфейсов, обеспечивающих реализацию контракта для внешних потребителей. У этих людей в голове мешанина, и они делают что-то в роде

Допустим, base.do_something владеет неким счётчиком base.something_count и мы его также используем в derived_one.do_specific_action. Это нарушает инкапсуляцию

То есть, даже когда они понимают, что делают что-то через жопу, их это совершенно не останавливает.

r--r--r--
()
Ответ на: комментарий от r--r--r--

> Object-oriented programming (OOP) is a programming paradigm based on objects … An OOP computer program consists of objects that interact with one another.

Объектно-ориентированное - то, что основано на объектах и состоит из объектов. А масло - то, что масляное и состоит из масла.

Вообще, каким был ООП 40 лет назад - это другая реальность. Современные популярные языки вроде C++/Java - не Smalltalk. Поэтому определение нужно более точное, поближе к тому, как именно языки реализуют ООП и как люди его используют и понимают. Мои «4 столпа» - определение упрощённое, но явно лучше тавтологии и достаточно, чтобы показать контраст на примере Си (именно в этом контексте было приведено определение).

> не понимают концепций инвариантов, обеспечивающих эти инварианты инкапсуляции, и публичных интерфейсов, обеспечивающих реализацию контракта для внешних потребителей

Я понимаю, что инвариантами обладают как публичный, так и внутренний интерфейс. Я учитывал эту разницу в сообщении, на которое вы отвечаете.

Вообще, раз уж вы знаете понятие «инвариант», может быть вспомните такие понятия как white-box и black-box?

> То есть, даже когда они понимают, что делают что-то через жопу, их это совершенно не останавливает.

На самом деле это обычный сценарий, ради которого protected и существует. Абсолютно штатный паттерн в языках с наследованием реализации.

Наследование реализации - это концепция, которая совмещает в себе переиспользование кода (зависимость от деталей реализации родителя) и отношение вида is-a. Размывается разница между (внутренними) обязательствами и тем, что задумывалась как скрытая кухня класса. И даже если мы чётко задокументируем инварианты *всех* членов, мы всё равно по сути зависим от деталей реализации: мы знаем об объекте намного больше, чем тот инкапсулировал, просто теперь с гарантиями.

Правильное решение с точки зрения дизайна языка - не смешивать внутренний контракт и зависимость от деталей реализации. А не уповать на то, что программист всезнающий и следит за всеми инвариантами в каждый момент времени. Это аргумент вида «просто не присваивай null туда, где он не должен быть».

kaldeon ★★
()
Последнее исправление: kaldeon (всего исправлений: 1)
Ответ на: комментарий от kaldeon

Правильное решение с точки зрения дизайна языка - не смешивать внутренний контракт и зависимость от деталей реализации.

Ага, ага. Теоретики херовы.

eao197 ★★★★★
()
Ответ на: комментарий от kaldeon

Объектно-ориентированное - то, что основано на объектах и состоит из объектов.

Всё ещё лучше твоей деревенской самодеятельности, тем более, что у тебя там ошибка буквально в каждом слове.

На самом деле это обычный сценарий, ради которого protected и существует. Абсолютно штатный паттерн в языках с наследованием реализации.

На самом деле это "обычный сценарий" только у безмозглых идиотов, не понимающих таких самых базовых вещей как "инварианты" и "публичный контракт". Тип (класс) публикует пользователям (включая наследников) контракт, который в C++ выражен через видимость public / protected. Пользователи (включая наследников!) не имеют доступа к внутреннему (private) состоянию класса. И не должны.

Твой идиотский аргумент со счётчиком аналогичен попытке доказать не нужность пожарной сигнализации на примере, где бракованные датчики не реагируют на появление дыма.

Размывается разница между (внутренними) обязательствами и тем, что задумывалась как скрытая кухня класса.

Нет, конечно же. Скрытая кухня скрыта за private и не доступна наследникам.

мы знаем об объекте намного больше, чем тот инкапсулировал,

Ты вообще ни черта не знаешь об объекте, кроме того, что опубликовано в описании класса, и доступа к закрытым членам класса, даже указанным в описании, у тебя нет.

Правильное решение с точки зрения дизайна языка

Правильное решение в твоём случае - не демонстрировать столь настойчиво такую вопиющую безграмотность и не пытаться сделать вид, что ты хоть на одну йоту квалифицирован достаточно, чтобы делать выводы о правильности дизайна языков программирования - слишком очевидно, что ты не.

r--r--r--
()
Ответ на: комментарий от r--r--r--

> у тебя там ошибка буквально в каждом слове

> На самом деле это «обычный сценарий» только у безмозглых идиотов

> Правильное решение в твоём случае - не демонстрировать столь настойчиво такую вопиющую безграмотность

Пустые слова

> аналогичен попытке доказать не нужность пожарной сигнализации на примере, где бракованные датчики не реагируют на появление дыма.

Метафора — не аргумент.

> Нет, конечно же. Скрытая кухня скрыта за private и не доступна наследникам.

private-член может обращаться к public-члену, который может быть переопределён в дочернем классе и непреднамеренно нарушить какой-либо инвариант, особенно если он не задокументирован.

Вы путаете понятия модификаторов доступа и зависимости от деталей реализации.

> Ты вообще ни черта не знаешь об объекте, кроме того, что опубликовано в описании класса, и доступа к закрытым членам класса, даже указанным в описании, у тебя нет.

Вы только что предоставили рецепт проблемы хрупкого класса. Если я «ничерта» не знаю о деталях реализации, значит я могу как угодно вертеть protected- и public- членами, нарушая сколько угодно инвариантов.

Наследование реализации предполагает, что наследник должен понимать не только интерфейс, но и ожидания базового класса относительно поведения, а это часто не формализовано и зависит от деталей реализации.

kaldeon ★★
()
Ответ на: комментарий от kaldeon

Пустые слова

Не корректная формулировка. Корректная - непонятные тебе лично. Либо ты не владеешь терминологией, либо не имеешь необходимых знаний, чтобы понять их смысл.

Метафора — не аргумент.

  1. Это не метафора, это - аналогия.
  2. Это не аргумент, это - иллюстрация.

private-член может обращаться к public-члену, который может быть переопределён в дочернем классе и непреднамеренно нарушить какой-либо инвариант,

Нет, не может, потому что дочерний класс не имеет доступа к закрытым членам базового класса. Интересно, сколько раз надо тебе повторить эту фразу из букваря по C++, чтобы она просочилась сквозь твой череп до мозга?

Если я «ничерта» не знаю о деталях реализации, значит я могу как угодно вертеть protected- и public- членами,

Да. В этом весь смысл инкапсуляции.

нарушая сколько угодно инвариантов.

Ты не можешь ничего нарушить, если инкапсуляция реализована корректно - в этом её смысл.

Вы путаете понятия модификаторов доступа и зависимости от деталей реализации.

Да нет, это ты тупо C++ не знаешь.

Наследование реализации предполагает, что наследник должен понимать не только интерфейс, но и ожидания базового класса относительно поведения,

Это частный случай более общего правила - пользуясь неким кодом, ты должен понимать ожидания среды выполнения относительно поведения. Тебе при int a = b + c; надо понимать / надеяться, что сумма не превысит допустимые значения.

Использование кода базового класса вообще ничем в этом месте не отличается от использования любого другого кода. Не понимаю, почему тебя на этом так заклинило. Точнее - моя рабочая гипотеза, что ты в упор не понимаешь концепции инвариантов и контрактов и поэтому не можешь себе представить корректную реализацию инкапсуляции. Отсюда и иррациональные тёплые чувства к Go.

r--r--r--
()
Ответ на: комментарий от r--r--r--

> > ожидания базового класса относительно поведения

> ты должен понимать ожидания среды выполнения относительно поведения

Это не просто «частный случай». Разница принципиальна. В случае с композицией мы можем нарушить ожидания другой стороны относительно поведения. В случае с наследованием у нас стирается чёткая грань между поведением и деталями реализации.

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

> > private-член может обращаться к public-члену, который может быть переопределён в дочернем классе и непреднамеренно нарушить какой-либо инвариант,

> Нет, не может, потому что дочерний класс не имеет доступа к закрытым членам базового класса.

Для того, чтобы нарушить внутренний инвариант, не обязательно иметь доступ к private-членам.

> Ты не можешь ничего нарушить, если инкапсуляция реализована корректно - в этом её смысл.

Если система спроектирована без ошибок, то ошибок не будет. Понятно.

* * *

Подведём итоги.

1. Вы считаете, что модификаторы доступа (синтаксическая зависимость) полностью решают проблемы инкапсуляции (семантической зависимости) при наследовании. Это напрямую противоречит академическим выводам [sny86], но вы считаете, что базовых знаний C++ достаточно.

2. Уклонились от рассмотрения понятий white-box и black-box.

3. Считаете, что при наследовании не нужно знать внутренние инварианты (они якобы «инкапсулированы»), но при этом уклоняетесь от проблемы хрупкого базового класса [1].

4. Не опровергли моё определение ООП и, что важнее, не продемонстрировали уместность своего определения в контексте данной дискуссии.

5. Вместо аргументов переходите на личности.

Поэтому я больше не буду вам отвечать.

[sny86]: Alan Snyder. Encapsulation and inheritance in object-oriented languages.

[1]: https://en.wikipedia.org/wiki/Fragile_base_class

kaldeon ★★
()
Ответ на: комментарий от kaldeon

Дочерний класс, не зная этого внутреннего инварианта, заменяет do_something на более простую реализацию.

Не во всех языках можно просто так взять и заменить любой метод базового класса в любом наследнике.

А те методы, которые можно переопределять, специальным образом помечаются как таковые и из-за этого требуют к себе особого внимания.

Это напрямую противоречит академическим выводам [sny86], но вы считаете, что базовых знаний C++ достаточно.

Во-первых, это очень и очень старые «академические выводы».

Во-вторых, беглый просмотр говорит о том, что это никакие нахрен не «выводы», а всего лишь обзор того немного, что было в области ООП в 1986-ом году. Более того, там вроде бы даже Eiffel не упомнинается (и понятно почему).

Т.е. весь 40 летний опыт последующего использования ООП в огромном количестве самых разнообразных ЯП и проектов в этой работе просто-напросто отсутствует.

Так что к вашему абстрактному словоблудию можно прилепить еще один ярлык «суждение черпает из забытых газет времен очаковских…»

eao197 ★★★★★
()
Ответ на: комментарий от eao197

> А те методы, которые можно переопределять, специальным образом помечаются как таковые и из-за этого требуют к себе особого внимания.

Это не опровергает мой главный тезис — наследование реализации принципиальным образом сильнее вредит инкапсуляции.

А найти способ смягчить проблему можно всегда.

> Во-вторых, беглый просмотр говорит о том, что это никакие нахрен не «выводы», а всего лишь обзор того немного, что было в области ООП в 1986-ом году. Более того, там вроде бы даже Eiffel не упомнинается (и понятно почему).

Попробуйте посмотреть не бегло, а вдумчиво. Это не столько обзор (автор — не блоггер), сколько анализ фундаментальных концепций ООП.

Eiffel не упоминается, скорее всего, потому что дата релиза публикации примерно совпадает с датой релиза языка. Но я кое-что знаю про Eiffel: при разработке этого языка было введено понятие Design by Contract [1], которое, в сущности, решало проблемы наследования реализации через принцип подстановки Лисков. То есть существование Eiffel подтверждает актуальность проблем, но решает их частично.

> Т.е. весь 40 летний опыт последующего использования ООП в огромном количестве самых разнообразных ЯП и проектов в этой работе просто-напросто отсутствует.

Звучит примерно как «весь 339 летний опыт последующего использования законов гравитации в работах Ньютона просто-напросто отсутствует».

Однако, если вы до сих пор не усвоили уроки 40-летней или 339-летней давности, значит вы живёте в ещё более старой реальности.

[1]: https://en.wikipedia.org/wiki/Design_by_contract

kaldeon ★★
()
Ответ на: комментарий от kaldeon

Это не опровергает мой главный тезис — наследование реализации принципиальным образом сильнее вредит инкапсуляции.

А сильнодействующие лекарства имеют больше побочных эффектов. И?

Если вам для спасения жизни нужны именно сильнодействующие лекарства, то вы с побочными эффектами смиритесь.

А если вы тупо употребляете сильнодействующие лекарства при малейших симптомах без консультации с врачем, то лекарства тут не при чем вообще.

Точно так же и с проектированием: у вас есть задача и есть набор инструментов. Какие-то инструменты позволяют решить задачу быстрее и проще с точки зрения затрат разработчика. То, что эти инструменты могут иметь негативные эффекты - это то же самое, как и побочные эффекты у сильнодействующих лекарств.

Только вот вы, похоже, принадлежите к лагерю тех теоретиГов, которые предпочтут запретить все, что может иметь нежелательные для вас побочные эффекты.

Это не столько обзор (автор — не блоггер), сколько анализ фундаментальных концепций ООП.

Фундаментальный анализ на 8 страницах? А не с больным ли на голову я сейчас общаюсь (в медицинском смыслы)?

Да и фундаментальный анализ ООП когда этому ООП было с десяток лет всего и в наличии были лишь эпизодические примеры его использования – это сильно.

То, что вы несете здесь пустопорожнюю пургу в стиле маркетологов-евангелистов за все хорошее против всего плохого я уже привык, но иногда вы удивляете еще сильнее.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

> предпочтут запретить все, что может иметь нежелательные для вас побочные эффекты.

Нет, я не буду говорить другим программистам как писать код, не будучи полностью осведомлённым в предметной области. Применение принципов — ответственность каждого индивида. Поэтому если вы уверены в том, что наследование — самая лучшая модель для решения вашей проблемы, флаг вам в руки.

Я лишь указывал на существенный недостаток инструмента. Этого достаточно, чтобы обосновать роль этого инструмента в дизайне конкретного языка.

> Фундаментальный анализ на 8 страницах?

Что вас удивляет? Впервые видите научную публикацию?

Объём работы напрямую зависит от целевой аудитории и широты исследования. В данном случае публикация адресована экспертам на тему одной проблемы.

kaldeon ★★
()
Ответ на: комментарий от eao197

> Да и фундаментальный анализ ООП когда этому ООП было с десяток лет всего и в наличии были лишь эпизодические примеры его использования – это сильно.

Есть ещё одна метрика, более важная: цитирования. Я, например, лично видел цитирование в GoF [1], а это уже работа 1994 года. И она до сих пор не теряет актуальность.

[1]: https://en.wikipedia.org/wiki/Design_Patterns

kaldeon ★★
()
Ответ на: комментарий от kaldeon

Я, например, лично видел цитирование в GoF [1], а это уже работа 1994 года. И она до сих пор не теряет актуальность.

Вы еще скажите, что книга банды четырех – это фундаментальный труд.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Да, я могу сказать, что GoF — фундаментальный труд.

GoF ввели понятие паттернов, оказали огромное влияние на индустрию, сделали общепринятым принцип “favor composition over inheritance.”

На всякий случай, определение фундаментальности: «Фундаментальное» обозначает то, от чего зависит всё остальное в определённом контексте.

kaldeon ★★
()
Ответ на: комментарий от kaldeon

«Фундаментальное» обозначает то, от чего зависит всё остальное в определённом контексте.

От этого фундаментального труда зависело насколько долго и глубоко сношали людей на собеседованиях.

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

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Здравый смысл — это простое и бессознательное применение логики. Другими словами, это достойная, но детская форма мышления. Здравого смысла недостаточно там, где требуются теоретические знания: интегрирование сложных проблем, работа с широкими абстракциями, прогнозирование будущего.

kaldeon ★★
()
Ответ на: комментарий от kaldeon

Здравого смысла недостаточно там

Простите, а вы откуда это знаете? Ну т.е. если называть вещи своими именами, то где вы и где здравый смысл?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

> . . . где вы и где здравый смысл?

Ищите ответ на этот вопрос сами, если хотите. Это не моя забота.

kaldeon ★★
()
Последнее исправление: kaldeon (всего исправлений: 1)
Ответ на: комментарий от ugoday

Так проектирование сверху вниз тоже плохая концепция. Ответственная за тонну плохого кода.

вы реально думаете, что космический корабль или реактивный двигатель или дом или город… проектируют снизу вверх???

это вообще как?

все подсистемы проектируются исходя из требований к самой системе. вы просто не построите космический корабль, начиная от швов на креслах, и заклепок на панели управления.

снизу вверх проектируют там, где неясен окончательный вид изделия, и даже порой его функции. то есть строим то, что получится.

alysnix ★★★
()
Ответ на: комментарий от kaldeon

Наследование в C++ или Java называется наследованием класса. Реализация — часть класса.

класс может быть

  1. чистым абстрактным. тогда вы должны его отнаследовать и реализовать абстракции.

  2. иметь скрытую реализацию. тогда вы можете его наследовать, а внутренние переделки не затронут размер класса, что обычно наиболее болезненно, и вызывает массовую перекомпиляцию. Для вас это как бы дефолтно реализованный интерфейс. Или дефолтный реализации интерфесов - это тоже плохо?

  3. не иметь вообще никакой реализации, в просто быть набором констант, других классов и типов. Тогда наследование такого класса даст особенно тщательный вариант инкапсуляции и контроля использования.

«Автомобиль есть средство передвижения» легко выражается интерфейсом Vehicle и классом Car, реализующим интерфейс. Наследование не нужно.

а подкласс от Car вы как потом напишете? значит вам придется писать интерфейс Car. автомобили бывают разные. например гоночные и грузовые. Как только ваша иерархия станет глубокой, а число понятий станет расти - вы замучаетесь дробить все на интерефейсы и реализации.

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

например. я пишу класс, что имеет приватные подклассы, и работает с ними. мне не нужна изоляция подклассов и гибкость интерфейсов, а нужна компактность кода и производительность.

Не Car и Bike имеют общий двигатель от Vehicle, а Car и Bike имеют двигатель через интерфейс Engine.

это вы так придумали. у vehicle двигатель необязателен, потоиу такое свойство не может быть у этого класса. может быть свойство has_engine(), engine_kind()

итак определяемся:

  1. Наследование нужно как воспроизведение семантики - is_a
  2. Для зерокост реюза общего кода с минимальными тавтологиями.
  3. для зерокост совместимости по указателю на базовый класс.
  4. для более тщательного подхода к инкапсуляции.
  5. и вообще это красиво.
alysnix ★★★
()
Ответ на: комментарий от alysnix

вы реально думаете, что космический корабль или реактивный двигатель или дом или город… проектируют снизу вверх???

Нет, нет, иногда, обычно да.

снизу вверх проектируют там, где неясен окончательный вид изделия, и даже порой его функции. то есть строим то, что получится.

Бинго! Сверх того, в отличие от ракетной техники, где законы физики обычно довольно стабильны, у нас есть бизнес-требования, законы и регуляции, которые меняются порой весьма хаотично. Так что в процессе космическая ракета может трансформироваться в теплоход на подводых крыльях. Который тоже ракета с определённой точки зрения.

ugoday ★★★★★
()
Ответ на: комментарий от kaldeon

Подведём итоги.

Да, давай, самое время - пора портфель в школу собирать.

  1. Вы считаете, что модификаторы доступа (синтаксическая зависимость) полностью решают проблемы инкапсуляции

Нет, конечно. Ты просто не понимаешь того, что тебе пишут. Ящитаю, что С++ даёт достаточный инструментарий, чтобы обеспечить инкапсуляцию на должном уровне. И явно лучше, чем Go. Это не "решает полностью проблемы инкапсуляции" - для этого мозги нужны. Но если мозгов нет, то никакой С++ не поможет - это точно.

  1. Не опровергли моё определение ООП

Определения не опровергают, их либо принимают, либо нет. Твою деревенскую самодеятельность никто кроме тебя не примет.

Если система спроектирована без ошибок, то ошибок не будет. Понятно.

Всё верно. И весь разговор идёт о том, что есть языки которые помогают минимизировать количество ошибок, а есть такие, которые даже не пытаются.

Разница принципиальна.

Ну, давай посмотрим, в чём она заключается?

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

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

Для того, чтобы нарушить внутренний инвариант, не обязательно иметь доступ к private-членам.

Обязательно. Я же говорю - ты тупо не понимаешь предмета разговора и не знаешь С++.

Считаете, что при наследовании не нужно знать внутренние инварианты

Можно, но не обязательно. Более того, 99% программистов ни малейшего понятия не имеют не только о конкретных инвариантах, но даже и об общих принципов реализации 99,9% кода, который они используют. Без этого было бы не возможно писать сколько нибудь крупные программы.

при этом уклоняетесь от проблемы хрупкого базового класса [1].
[1]: https://en.wikipedia.org/wiki/Fragile_base_class

Мне просто любопытно, ты сам-то пробовал для интереса читать текст по собственным ссылкам?

One possible solution is to make instance variables private to their defining class and force subclasses to use accessors to modify superclass states. A language could also make it so that subclasses can control which inherited methods are exposed publicly. These changes prevent subclasses from relying on implementation details of superclasses

Давай я обведу тебе нужные буковки:

These changes prevent subclasses from relying on implementation details of superclasses

И ещё подчеркну:

THESE CHANGES PREVENT SUBCLASSES FROM RELYING ON IMPLEMENTATION DETAILS OF SUPERCLASSES

И выделю жирненьким:

THESE CHANGES PREVENT SUBCLASSES FROM RELYING ON IMPLEMENTATION DETAILS OF SUPERCLASSES

Я, правда, уверен, что и в таком виде до твоего мозга ни йоты из написанного не просочится. Если господь не дал, то не судьба.

Поэтому я больше не буду вам отвечать.

Спасибо. А ты мог бы еще и вообще не писать? Если не в интернете, то хотя бы на лоре? Ну, сделать одолжение окружающим. Помочь им, так сказать.

r--r--r--
()
Вы не можете добавлять комментарии в эту тему: только для зарегистрированных, score>=50.