LINUX.ORG.RU

Более лучшие типы

 


0

2

Одна из известнейших персон CS, американский учёный в области вычислительной техники, директор по исследованиям корпорации Google,член Совета Американской ассоциации искусственного интеллекта, Питер Норвиг отмечает бесспорные преимущества первоклассных динамических типов:

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

Типы или классы являются объектами времени исполнения (не только времени компиляции)

Переменные могут иметь типы в качестве своих значений

Типы и классы могут быть созданы/изменены в рантайме

Мы имеем функции для манипуляции типами/классами, а также выражения для создания безымянных типов.

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

http://norvig.com/design-patterns/design-patterns.pdf стр 11



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

Ты сам себе противоречишь. Рантаймовые first-class типы можно рссматривать, в том числе, как часть оптимизации, как раз на уровне архитектуры.

javaQest
() автор топика
Ответ на: комментарий от loz

Не нужно тут придумывать никаких компромиссов. Идея проверки корректности программ — это идея фикс, это ясно с самого начала. Это все та же «проблема» останова, вид сбоку. Надо поворачивать на 180 градусов и выкидывать вообще всю статику к чертям. То что делает тайп чекинг в компилтайме, все это можно сделать и в рантайме, в самом начале, при условии, что исходный код программы в рантайме будет доступен. Это можно сделать «по месту», на коленке, и это может сделать сам разработчик, исходя из своих конкретных нужд, для этого не нужны никакие говарды сраные, и сделать это намного тоньше и гибче.

javaQest
() автор топика
Ответ на: комментарий от javaQest

каким образом усложнение обработки и лишние структуры с данными могут рассматриваться как «оптимизация»? усложнение кода на уровне архитектуры только тормозит всю систему. хранение лишних данных о типах жрёт ресурсы и отнимает время на обработку.

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

Оно может и так, но спится как-то спокойнее, когда на продакшен выкатили скомпиленную версию с проверенными типами. Тесты, разумеется, тоже присутствуют и все вот это вместе.

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

Шизофреник, зачем ты имеешь мнение по важным вопросам, если ты ни строчки полезного кода за свою жалкую жизненку не написал? Уйди отсюда, ты тупой и неграмотный.

anonymous
()
Ответ на: комментарий от Iron_Bug

Если тебе нужна эта «лишняя» структура, ты от нее никуда не денешься, ты просто сделаешь все через жопу, чтобы обойти ограничения языка. В рантайме, в определенный момент, окажется ясно, что часть того, что запилено изначально, уже точно не потребуется, и ты освободишь память и оптимизируешь поиск. Либо наоборот, структуры, которые потребуются, могут быть созданы прямо в рантайме, и соответственно, если они не потребовались, они просто не будут созданы.

усложнение

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

javaQest
() автор топика
Ответ на: комментарий от anonymous

Я ничего не понял, Капитан Запутанность. Выше по треду для вас есть бесплатный совет от гениального анонiмуса. :-)

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

тебе же популярно объяснили, что информацию о типах хранят сами типы

И где они её хранят? В астрале? Или быть может в памяти?

Смотри, допустим есть 4 байта в памяти - FF 3F 22 65. Что это? signed int? unsigned int? float? Или быть может char[4]? В компилируемых языках этот момент разруливает компилятор и хардкодит нужную инструкцию для доступа к этим байтикам, исходя из того как объявили переменную. Если же тип задаётся динамически, то это перестаёт быть возможным. Нужно добавить к каждой переменной какой-то идентификатор типа, чтобы знать, как к ней обращаться. А теперь представим, что у нас не скалярный тип, а какой-нибудь класс. Это ж надо сохранить всю иерархию наследования (чтобы знать к чему его приводить можно, а к чему нельзя и как именно) и таблицы методов (даже тех, которые нифига не виртуальные). Да, можно хранить отдельно информацию о типе, а к переменной прикладывать только ID в таблице типов. Но это всё равно оверхед по памяти, да и на сложном проекте таблица всех классов со всех их атрибутами тоже не маленькая может получится.

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

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

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

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

По моему, ты вообще не понимаешь, как это работает. В динамических языках все разрешается в рантайме. Не надо хранить никакой информации нигде. Иными словами, тип List никогда не знает, что означает его слот «first» сегодня, и что он будет означать завтра.

единственное, что надо «знать» объекту — это ссылка на родителя(ей)

и хардкодит

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

javaQest
() автор топика
Ответ на: комментарий от KivApple

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

javaQest
() автор топика
Ответ на: комментарий от javaQest

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

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

Я не про хаскель и джаву, а про какой-нибудь C++.

Не надо хранить никакой информации нигде.

Окей. У нас есть объект myList. Мы хотим вызвать его метод append. Как это произойдёт? В C++ два варианта. Если метод виртуальный, то получится call myList->vTable[N] (где N - константа, известная на этапе компиляции). Накладные расходы по памяти - один указатель на каждый виртуальный метод для каждого экземпляра класса. Если метод не виртуальный, то будет call myList_append, где myList_append - константный адрес, известный на этапе компиляции. Накладных расходов по памяти нет в принципе.

А что будет в твоём случае?

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

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

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

anonymous
()
Ответ на: комментарий от KivApple

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

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

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

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

JIT? Нет, не слышали.

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

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

javaQest
() автор топика
Ответ на: комментарий от mix_mix

потому что в статике «ненастоящее» наследование. Общее использование одного и того же кода там — это фейк, на самом деле наследование реализуется, по большей части не делегированием, а тупым копированием со статическим связыванием. Соответственно, каждая копия слота требует своей памяти.

javaQest
() автор топика
Ответ на: комментарий от javaQest

тупым копированием со статическим связыванием

Что-то я не распарсил. У нас есть класс A, у него есть vtbl с функциями foo (0x100), bar (0x200) и baz (0x300), в скобках адреса функций в памяти. Вызов a->foo(...) в компайл-тайме раскрывается в (a->(*vptr)[0])(a, ...). Потом у нас есть наследник B, у него есть своя vtbl с функциями foo (0x400), bar (0x200), baz (0x300) и quux (0x500), по адресам поведение уже должно быть понятно — foo замещается, остальные остаются от предка, добавляется новая quux. Вызов b->foo(...) ничем не отличается: (b->(*vptr))[0](b, ...). Ты это имел в виду? Что вся vtbl копируется? Ну так мы гораздо меньше всасываем на производительности, для вызова виртуальной функции нам нужно в худшем случае разыменовать всего три указателя (ссылка на экземпляр класса, vptr и vtbl[n]). Попробуй описать на таком же уровне, как это будет выглядеть в динамике.

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

К слову, подумай почему в такой схеме каст b к A полностью бесплатный.

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

Ну так мы гораздо меньше всасываем на производительности

А я и не утверждал, что производительность в динамике лучше. Речь шла исключительно о памяти.

javaQest
() автор топика
Ответ на: комментарий от mix_mix

Попробуй описать на таком же уровне, как это будет выглядеть в динамике

А в динамике очень просто. есть класс А, который имеет метод (содержит ссылку на него) b, есть класс B, который содержит ссылку на A, как на родителя. при вызове B.b имя сначала будет искаться в B, затем в A, находится, вызывается (в контексте B)

javaQest
() автор топика
Ответ на: комментарий от javaQest

А давай всё-таки прикинем сколько уходит памяти. Раз мы можем в рантайме добавлять методы, просто массивом адресов уже не обойтись, нам нужно хранить где-то и их имена, верно?

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

Представляешь, как мы всосём здесь на кэшах? Но-таки да, речи о производительности не было.

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

А давай всё-таки прикинем сколько уходит памяти. Раз мы можем в рантайме добавлять методы, просто массивом адресов уже не обойтись, нам нужно хранить где-то и их имена, верно?

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

javaQest
() автор топика
Ответ на: комментарий от javaQest

Конечно, жрёт: в хешах во-первых, есть некое относительно фиксированное количество корзин N, так, что мы можем выбирать слот путём операции hash(name) % N, а во-вторых, в хешах практически неизбежны коллизии, поэтому хранить полное имя метода нам всё равно придётся, как ни крути.

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

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

мы стали более лучше одеваться ;)

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от javaQest

Статическая проверка никак не мешает быть типам в рантайме (часть проверок будет так же в рантайме, обв). Че там точно в жабе я не знаю.

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

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

...написав 100500 тестов, уровня проверки корректности a.length vs a.lengdth. Очень удобно и «по месту».

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

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

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

И как в Objective-C в рантайме создать тип bigint и класс с эффективными методами для работы с этим бигинтом? Откуда эти методы возьмутся? Их надо будет скомпилировать в машинный код, чтобы все это эффективно работало.

SZT ★★★★★
()

Не читал, но осуждаю. Времена чистого инженерного подхода в CS уже проходят...

А для любителей динамики предлагаю простейшую задачу: сделать преобразование unranked-дерева (в любой удобной форме) в extension-encoded форму. За подробностями в TATA. Затем — для осознания получившегося результата — немного с ним поработать, например сделать список всех узлов при обходе (т.н. yield) или сделать из него Graphviz.

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

один указатель на каждый виртуальный метод для каждого экземпляра класса

для каждого

уроки сделал?

anonymous
()

Когда делается акцент на отмечании бесспорных преимуществ, то они уже не так ж и бесспорны. Особенно когда не понимают разниц между типом и значением, между классами типами и объектами ...

Оберон, модула, ада, виста, вин8-10 тоже отмечались бесспорными преимуществами ...

anonymous
()
Ответ на: комментарий от SZT

Создать класс NSBigInt, замапить селекторы на соотв. функции GMP/MPFR через прокси-враппер. Точно также можно взять любой класс другой среды и замапить его в объектив рантаймовым биндером, который знает об ртти той среды. Ты путаешь создание кода (который тоже придется «знать» как и зачем создавать) и композицию существующего. Тащемта все классы объектива, кои сами являются объектами, создаются в рантайме при подключении .so с набором классов (ака фреймворк) и при запуске основного исполняемого.

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

Создать класс NSBigInt, замапить селекторы на соотв. функции GMP/MPFR через прокси-враппер.

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

Типы и классы могут быть созданы/изменены в рантайме

то я это понимаю так, что сам исполняемый код методов класса может быть изменен/создан в рантайме (JIT).

Допустим мы написали некий недо-bigint в котором реализованы операции + - но не реализовано / * % power(). Вот запустили мы такой код и ходим изменить класс в рантайме, добавив в него наши / * % power() но самой реализации этих методов класса в откомпилированном виде просто НЕТ.

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

то я это понимаю так

Если так понимать, то все верно говоришь. Но когда так говорят, имеют ввиду не это, потому что этого просто не существует.

Нет никакой разницы, сгенерился ли машинный код в рантайме, был скомпилирован заранее, или же исходный код был подключен через стандартный бридж к внешней среде (питон/луа/лисп/etc). Никто не генерит код из /dev/random, он все равно в каком-то виде *уже* есть, пусть хоть в виде объектов интерпретер-стейта, хоть жестко зажиченый в натив. Ты можешь при подключении питон-плагина создать класс, методы которого будут отмаплены в функции из стейта питона, которые там появились в результате eval(modaldialog.textfield). А потом засунуть объект этого класса куда-то, где нужен соотв. интерфейс и все заработает, как если бы он был написан заранее. В этом вся суть.

anonymous
()
Ответ на: комментарий от Iron_Bug

излишние навороты на уровне архитектуры всегда плохи

Плохи для кого? Ниже планка, больше гибкость, индусы быстрее быдлокодят. Все супер. Если бы индусы и прочие «плохие программисты» без культуры программирования не устраивали работодателей их бы перестали нанимать.

anonymous
()
Ответ на: комментарий от javaQest

180 градусов и выкидывать вообще всю статику к чертям

Не, лучше тебя выкинуть.

crutch_master ★★★★★
()

Не вижу какого-то большого профита от динамической типизации. Преобразования неявны и надо хорошо понимать что там под капотом, чтобы не сесть в лужу. При разборе чужого кода вообще не понятно кто какие параметры берёт и что возвращает. Смотришь на переменную и задаёшь вопрос: «а это что?», а ответ - да всё, что угодно: строка, число, класс, функция. Где посмотреть что передавать? Где-то в дебрях говнокода. Уникальная возможность присвоить $i сначала число, потом функцию, а затем строку - это вообще смешно.
Вышеперечисленное хорошо в чём-то для метапрограммирования, но не для работы, где есть чёткая задача, решение и результат. В такой ситуации все это в лучшем случае не нужно избыточно.

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

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

Динамика и неявные преобразования связаны чуть менее чем никак.

Смотришь на переменную и задаёшь вопрос:

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

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

Т.о. уже можно сформулировать одно преимущество динамики - она приучает к дисциплине

Динокурятина кудахтает о дисциплине, надо же. Если что, лучше всего к дисциплине приучает компилятор со статическими типами.

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

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

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

Динамика и неявные преобразования связаны чуть менее чем никак.

«1»+2 - это что, сложение или склеевание строк? А если «с»+2?

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

во в динамике нет даже этого.

это смотря в каком яп. В Io, например, вообще вся информация доступна прямо в рантайме, вплоть до исходного кода.

«1»+2 - это что, сложение или склеевание строк? А если «с»+2?

А при чем тут динамика? Это приведение типов.

javaQest
() автор топика
Ответ на: комментарий от tailgunner

Если что, лучше всего к дисциплине приучает компилятор со статическими типами.

Еще она неплохо приучает ходить строем, и всей толпой кукарекать о преимуществах статики, это тоже часть этой дисциплины. Хомячек боиться лишиться работы.

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

javaQest
() автор топика
Ответ на: комментарий от javaQest

Если что, лучше всего к дисциплине приучает компилятор со статическими типами.

Еще она неплохо приучает ходить строем, и всей толпой кукарекать о преимуществах статики

Это лучше, чем одиноко кукарекать о преимуществах динамики.

Грань между статикой и динамикой — это та грань, где кончается тупая писанина кода, и начинается программирование.

Охренеть, электромонтер учит программировать.

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

Это лучше, чем ходить толпой и кукарекать о преимуществах динамики.

что то я не наблюдаю этого. толпа — это как раз статик-бараны. Кто пишет на динамике обычно самодостаточен.

Охренеть, электромонтер учит программировать.

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

javaQest
() автор топика
Ответ на: комментарий от javaQest

Это лучше, чем ходить толпой и кукарекать о преимуществах динамики.

что то я не наблюдаю этого

Да, ты ходишь один, кукарекаешь о преимуществах динамики и показываешь фокусы на жабаскрипте. Но ты даже не клоун, а просто посмешище.

зря ты на электромонтеров наезжаешь

Я наезжаю на ровно одного упоротого электромонтера, которому снится, что он программист.

tailgunner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.