Здравствуйте, samius, Вы писали: FDS>>Тогда я могу назвать операцией типизации конструкцию if a mod 2 then ?
S>Вы — можете. Уверен в этом теперь.
И как же провести грань между одной условной веткой и другой, где так же определяется некоторое условие, без какой-либо явной процедуры получения имени или другого идентификатора типа?
S>Иначе может оказаться что вылетит операция диспетчеризации метода сложения
Так оно и должно быть, если мы говорим о строгой типизации, хоть и без типов .
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, FDSC, Вы писали:
FDS>>Это я их назвал, но это не значит, что они объявлены специально как целое 32-битное число и т.п.
AVK>Если эти термины имеют какой то смысл в контексте языка (не реализации), то таки типы есть.
А если не имеют? Грубо говоря, язык имеет стандартные наборы методов для int, String и decimal, но никак их не различает (т.е. я могу для decimal взять и определить метод print как-будто это String и будет у меня на экран выводится бессмысленные символы)
FDS>> То бишь для компилятора разница лишь в том, какие методы объявлены в этих объектах
AVK>Все, как только компилятор знает про объявленные методы, сразу же имеем типы. Единственная возможность поиметь полиморфизм операторов без типов — язык, в котором методы привязываются к экземплярам в рантайме.
Здравствуйте, FDSC, Вы писали:
AVK>>Если эти термины имеют какой то смысл в контексте языка (не реализации), то таки типы есть.
FDS>Грубо говоря, язык имеет стандартные наборы методов для int, String и decimal
Стандартный набор методов и есть тип.
FDS>Я о таком языке и говорю.
Здравствуйте, FDSC, Вы писали:
FDS>Здравствуйте, samius, Вы писали:
S>>object*object -> object. S>>Много чего сказало это компилятору о том как хранить данные?
FDS>Столько, сколько ему нужно. Это сказало компилятору, что нужно выделить 8 байт в стеке для аргументов и байта на результат (для 32-битной архитектуры)
А что это сказало компилятору о том, как процедура хранит переданные ей аргументы после вызова? Мы ведь все еще о процедурных типах данных здесь говорим, не так ли?
S>>>>Прямо туда — это куда?
FDS>>>В поле типа String. Всегда вместо этого объявляется делегат, интерфейс или объект, приводимый к String S>>Я тоже не встречал такого бреда — в поле типа String засунуть процедуру. Спишем это на позднее время
FDS>Ну вот, а значит когда мы объявляем вызов функции, которая возвращает строку, то это не то же самое, что объявление строки
Кто-то утверждал обратное?
S>>Не исключаю что функция object*object -> object положит аргументы в словарь и вернет словарь. А может положить их в список и вернуть список, а может записать их в файл и вернуть хэндл файла. Так что сигнатура и соглашение не говорят ничего компилятору о способе хранения переданных данных.
FDS>Говорят. Я уже писал, выше в этом сообщении и в предыдущем сообщении, но ты невнимательно прочитал. FDS>Объявление функции object * object -> object говорит компилятору, что он делает приращение вершины стека на 2 указателя (8-мь или 16-ть байт, в зависимости от архитектуры), определяет место под результат в виде 1 указателя, ставит команду call на месте вызова функции и передаёт ей указатель на эту функцию. А если ты хочешь, чтобы в одной строчке программы сразу объявить как и что она делает и хранит, то ты многого хочешь. Достаточно того, что компилятор из этой строки узнал новую и необходимую для него информацию.
Процедурные типы данных и соглашения о вызове метода не имеют ничего общего.
FDS>>>О способе получения — да, так как мы должны вызвать функцию и отвести место, куда будем получать результат (если результат сложный — то место под указатель на результат) S>>мы должны вызвать функцию, чтобы получить данные обратно. Зачем об этой функции что-то знать компилятору? FDS>Чтобы её правильно вызвать, как ты понимаешь.
Правильно вызвать — это одно, а то как хранит процедура переданные ей данные — это другое.
Здравствуйте, FDSC, Вы писали:
FDS>Здравствуйте, AndrewVK, Вы писали:
FDS>>> То бишь для компилятора разница лишь в том, какие методы объявлены в этих объектах
AVK>>Все, как только компилятор знает про объявленные методы, сразу же имеем типы. Единственная возможность поиметь полиморфизм операторов без типов — язык, в котором методы привязываются к экземплярам в рантайме.
FDS>Я о таком языке и говорю.
T>>Хранение — бесспорно, спасибо. S>Здесь есть варианты. Например, процедурные типы данных. Очевидно, что процедура имеет тип, но этот тип ничего не говорит компилятору/интерпретатору о способе хранения данных. Тип процедуры не то же самое, что тип данных, тем не менее процедуры позволяют хранить данные в форме отличном от "словаря переменных".
Интересно, а разве с процедурой не проще, наоборот?
Имя (чтоб вычислить entry point позже) или сразу ссылка на начало кода, да список типов аргументов, нет?
T>>Ещё интересно подробнее про "приводить типы вверх по дереву и унифицированно обращаться с ними". Система типов позволяет приводить типы вверх по дереву. Честно говоря, я не понял фразу. S>Речь идет о дереве наследования в традиционных ООП языках, т.е. интерпретация производных типов в качестве базовых. Кроме приведения upcast существует и приведение downcast. Система типов в случае downcast-а должна контроллировать корректность приведения.
Да, но это все равно что: компьютеры решают все проблемы, которых до их изобретения не существовало. Нет системы типов — не нужно ходить по дереву. Тут вроде никакая проблема/задача не решается. Вот проверка корректности и с типами нужна, и без.
T>>И про это тоже: "предоставлять стандартные интерфейсы без реализации". В гипотетическом языке каждый объект это словарь имя:метод (хороший пример — Javascript). Вы вызываете метод length, чтобы получить длину объекта dreams (допустим это список снов). Не совсем понятно, имеет ли тут место "предоставление интерфейсов" или нет. Вроде всё работает, в документации описан интерфейс: length :: Object -> Int, однако назначать для этого специальный тип объекту dreams не нужно. S>Здесь опять-таки слово интерфейс употребляется в контексте традиционных ООП языков. Аналог в хаскеле — класс типов, т.е. декларация того, что для некоторых типов должна существовать совокупность методов.
Я понял в каком смысле слово "интерфейс", не понял в каком смысле система типов их "предоставляет" и привёл пример утиной типизации, когда интерфейс декларируется только в документации. Да, статическая проверка корректности затруднена. Не уверен, это ли FDSC имел в виду.
T>>Допустим также, что в каких-то двух объектах a и b есть метод "+". Какую сигнатуру имеет этот метод?
FDS>Оператор плюс, насколько мне помнится, всегда был бинарным, сигнатуру имеет, соответственно, в виде двух объектов (любого типа, так как типизации у нас нет)
T>>Допустим, что a это число 5, а b это число 3. Очевидно, что в этих объектах "методы + одинаковые". Какова последовательность действий (логических выводов?) компилятора чтобы применить реализацию plus_int_int :: Int -> Int -> Int?
FDS>Я думаю правильней object * object -> object
Речь не об интерфейсе полиморфичного оператора +, а о реализации оператора + для двух чисел. Например, x86 ADD. Она оперирует числами, а не объектами...
FDS>a и b есть два параметра, результат является вызовом функции, представляющей реализацию оператора "+" FDS>Например, FDS>a и b — числа FDS>Тогда им соответствует функция сложения именно двух чисел (например, ассемблерная вставка или побитовое сложение соответствующей области памяти ) FDS>a и b — строки FDS>Тогда им соответствует функция конкантенации, т.е. совмещения двух областей памяти в одну последовательно.
FDS>Интерпретатор ищет функцию "+", подставляет a и b в неё и получает некий результирующий объект. Всё (при динамической типизации). FDS>Я что-то упустил?
... и, соответственно, вопрос был в том как на основании двух одинаковых + :: Object -> Object -> Object компилятор узнает, что нужно подставить ADD, на какие ячейки памяти нужно ссылаться. Давайте попытаемся представить себе действия компилятора.
Дальше вы сказали, что компилятор видит, что методы одинаковые, и на основании этой одинаковости предпринимает какое-то решение (в этом заключается вопрос), на основании которого генерится код типа
Выход:
ADD d x y # где ADD это какая-то низкоуровневая функция, принимающая два числа, а x и y это числа из объектов a и b.
Вот объясните, что делает компилятор после обнаружения, что методы одинаковые, как получается результат?
Здравствуйте, FDSC, Вы писали:
FDS>Здравствуйте, samius, Вы писали: FDS>>>Тогда я могу назвать операцией типизации конструкцию if a mod 2 then ?
S>>Вы — можете. Уверен в этом теперь.
FDS>И как же провести грань между одной условной веткой и другой, где так же определяется некоторое условие, без какой-либо явной процедуры получения имени или другого идентификатора типа?
Когда я отвечал на это
FDS>>>Т.е. это означает, что объект в этой толпе языков имеет множество типов вне одной ветки дерева, а так же информация об этом неявно типе где-то хранится, или нет?
S>>Нет, не означает
Я подразумевал то, что информация о типе может быть у программиста в голове, и что компилятор/интерпретатор действительно не знает и не проверяет типы.
причем тут ветвление и проверка деления на 2 — у меня даже догадок нет.
S>>Иначе может оказаться что вылетит операция диспетчеризации метода сложения
FDS>Так оно и должно быть, если мы говорим о строгой типизации, хоть и без типов .
Ну да. В итоге получаем что наличие ассоциации с операцией сложения у двух операндов не обязательно.
Здравствуйте, Temoto, Вы писали:
T>>>Хранение — бесспорно, спасибо. S>>Здесь есть варианты. Например, процедурные типы данных. Очевидно, что процедура имеет тип, но этот тип ничего не говорит компилятору/интерпретатору о способе хранения данных. Тип процедуры не то же самое, что тип данных, тем не менее процедуры позволяют хранить данные в форме отличном от "словаря переменных".
T>Интересно, а разве с процедурой не проще, наоборот?
Менее эффективно, как правило — это да. Проще — не знаю. Что есть проще и для кого?!?!?
S>>Речь идет о дереве наследования в традиционных ООП языках, т.е. интерпретация производных типов в качестве базовых. Кроме приведения upcast существует и приведение downcast. Система типов в случае downcast-а должна контроллировать корректность приведения.
T>Да, но это все равно что: компьютеры решают все проблемы, которых до их изобретения не существовало. Нет системы типов — не нужно ходить по дереву. Тут вроде никакая проблема/задача не решается.
апкастами и даункастами проверка корректности и решается.
T>Вот проверка корректности и с типами нужна, и без.
Нужна-то нужна, но необходимой она является только для статически типизированных языков.
S>>Здесь опять-таки слово интерфейс употребляется в контексте традиционных ООП языков. Аналог в хаскеле — класс типов, т.е. декларация того, что для некоторых типов должна существовать совокупность методов.
T>Я понял в каком смысле слово "интерфейс", не понял в каком смысле система типов их "предоставляет" и привёл пример утиной типизации, когда интерфейс декларируется только в документации. Да, статическая проверка корректности затруднена. Не уверен, это ли FDSC имел в виду.
T>>>>Хранение — бесспорно, спасибо. S>>>Здесь есть варианты. Например, процедурные типы данных. Очевидно, что процедура имеет тип, но этот тип ничего не говорит компилятору/интерпретатору о способе хранения данных. Тип процедуры не то же самое, что тип данных, тем не менее процедуры позволяют хранить данные в форме отличном от "словаря переменных".
T>>Интересно, а разве с процедурой не проще, наоборот? S>Менее эффективно, как правило — это да. Проще — не знаю. Что есть проще и для кого?!?!?
Да, "проще" — не то слово.
Я имел в виду, что несмотря на то, что варианты есть, разве с процедурами не всё очевидно? Разве есть какие-то камни в хранении имени и списка параметров? Выглядит не сложнее, чем хранить значение, например, длинного числа.
Здравствуйте, Temoto, Вы писали:
T>>>>>Хранение — бесспорно, спасибо. S>>>>Здесь есть варианты. Например, процедурные типы данных. Очевидно, что процедура имеет тип, но этот тип ничего не говорит компилятору/интерпретатору о способе хранения данных. Тип процедуры не то же самое, что тип данных, тем не менее процедуры позволяют хранить данные в форме отличном от "словаря переменных".
T>>>Интересно, а разве с процедурой не проще, наоборот? S>>Менее эффективно, как правило — это да. Проще — не знаю. Что есть проще и для кого?!?!?
T>Да, "проще" — не то слово.
T>Я имел в виду, что несмотря на то, что варианты есть, разве с процедурами не всё очевидно? Разве есть какие-то камни в хранении имени и списка параметров? Выглядит не сложнее, чем хранить значение, например, длинного числа.
Не понимаю, что имеется в виду под хранением имени и списка параметров.
Я имел в виду нечто вроде определений cons отсюда, когда процедура используется вместо структуры данных и даже вместо чисел (см. Church numerals там же). Здесь хранятся не имена и списки параметров, а замыкания, либо представление параметров в виде произведения простых делителей... В этом примере определяющим способ хранения является не тип структуры данных, а именно способ представления, задаваемый совокупностью конструктора и селекторов.
Здравствуйте, samius, Вы писали:
S>Когда я отвечал на это
... S>Я подразумевал то, что информация о типе может быть у программиста в голове, и что компилятор/интерпретатор действительно не знает и не проверяет типы.
S>причем тут ветвление и проверка деления на 2 — у меня даже догадок нет.
Информация о типе, хранящаяся в голове программиста — это абстракция. Т.е. у компилятора, получается, системы типов технологически нет, соответственно и функции она никакой в языке не играет.
S>Ну да. В итоге получаем что наличие ассоциации с операцией сложения у двух операндов не обязательно.
При условии, что определён порядок применения этой операции.
Здравствуйте, Temoto, Вы писали:
FDS>>Я думаю правильней object * object -> object
T>Речь не об интерфейсе полиморфичного оператора +, а о реализации оператора + для двух чисел. Например, x86 ADD. Она оперирует числами, а не объектами...
Ну и? В чём сложность объявить такую операцию? Это просто функция сложения, которая будет вызвана именно для тех объектов, для которых определена именно функция сложения (она может быть базовой в компиляторе или выполнена на ассемблерных вставках)
T>... и, соответственно, вопрос был в том как на основании двух одинаковых + :: Object -> Object -> Object компилятор узнает, что нужно подставить ADD, на какие ячейки памяти нужно ссылаться. Давайте попытаемся представить себе действия компилятора.
1. Есть указатели на объекты a и b
2. В этих объектах хранятся данные объекта в двух возможных вариантах: а) сами данные объекта как первичного типа (секция неименованных данных) б) объекты-поля в словаре полей (секция именованных полей)
3. В этих объектах хранится словарь методов, которые принимают указатели на объекты и заранее известно для каждого метода, сколько указателей принимает, и сколько возвращает
Тогда
1. Компилятор находит объекты a и b как операнды оператора "+".
2. В зависимости от соглашения, допустм, сравнивает, имеют ли a и b методы "+" и если имеют, равны ли они (совместимы ли) или просто вызывает один из методов по заранее определённому соглашению (мне нравится первый вариант, но samius указал на возможность и второго)
3. Вызов метода происходит следующим образом: в него передаются два указателя на объект, сохраняется место для результата-объекта
4. Метод реализован так, что читает данные обоих аргументов-объектов из секции неименованных данных, сам метод знает, что они 32-разрядные и передаёт два 32-разрядных числа в операцию add процессора.
5. Получив результат создаёт новый объект, куда записывает получившийся результат в секцию неименованных данных, а так же указатели на методы, соответствующие соглашению (назначению метода)
T>Вход: выражение a + b. T>
T>Дальше вы сказали, что компилятор видит, что методы одинаковые, и на основании этой одинаковости предпринимает какое-то решение (в этом заключается вопрос), на основании которого генерится код типа
Не понял вопроса.
T>Выход: T>ADD d x y # где ADD это какая-то низкоуровневая функция, принимающая два числа, а x и y это числа из объектов a и b.
Выход — это уже новый объект с числом d. Кстати, раньше add не принимала целых три аргумента. Это я так, к слову
T>Вот объясните, что делает компилятор после обнаружения, что методы одинаковые, как получается результат?
Здравствуйте, AndrewVK, Вы писали:
FDS>>Грубо говоря, язык имеет стандартные наборы методов для int, String и decimal
AVK>Стандартный набор методов и есть тип.
Нет. Я могу выбрать из этого стандартного набора любое сочетание, например, метод print, предназначенный для int, запихнуть в объект, содержащий фактические данные типа decimal и метод + для типа decimal
FDS>>Я о таком языке и говорю.
AVK>Ну как то ты очень непонятно об этом говоришь.
Надо читать все сообщения темы, тогда будет понятно, я думаю.
Здравствуйте, samius, Вы писали:
AVK>>>Все, как только компилятор знает про объявленные методы, сразу же имеем типы. Единственная возможность поиметь полиморфизм операторов без типов — язык, в котором методы привязываются к экземплярам в рантайме.
FDS>>Я о таком языке и говорю.
S>http://en.wikipedia.org/wiki/Type_system#Dynamic_typing
И? Судя по определению, это не динамически типизированный язык.
Здравствуйте, samius, Вы писали:
S>А что это сказало компилятору о том, как процедура хранит переданные ей аргументы после вызова? Мы ведь все еще о процедурных типах данных здесь говорим, не так ли?
Всё сказало, т.к. процедура хранит аргументы так, как ей передал компилятор и больше никак. Тип функции является указанием на то, как компилятор хранит аргументы в момент их передачи, т.к. передача аргументов в функцию есть сохранение этих аргументов в стеке или регистрах процессора, в зависимости от соглашения о вызовах.
FDS>>Ну вот, а значит когда мы объявляем вызов функции, которая возвращает строку, то это не то же самое, что объявление строки
S>Кто-то утверждал обратное?
Да, ты утверждал, что
Очевидно, что процедура имеет тип, но этот тип ничего не говорит компилятору/интерпретатору о способе хранения данных.
Процедурный тип говорит компилятору, что у него нет объекта String, т.е. указывает его способ получения. Если бы процедурный тип ничего не говорил компилятору о способе хранения данных, то мы могли бы записать указатель на процедуру прямо в String, или наоборот, String в указатель на процедуру — компилятор бы не различал объекты String и сами процедуры.
S>>>Не исключаю что функция object*object -> object положит аргументы в словарь и вернет словарь. А может положить их в список и вернуть список, а может записать их в файл и вернуть хэндл файла. Так что сигнатура и соглашение не говорят ничего компилятору о способе хранения переданных данных.
FDS>>Говорят. Я уже писал, выше в этом сообщении и в предыдущем сообщении, но ты невнимательно прочитал. FDS>>Объявление функции object * object -> object говорит компилятору, что он делает приращение вершины стека на 2 указателя (8-мь или 16-ть байт, в зависимости от архитектуры), определяет место под результат в виде 1 указателя, ставит команду call на месте вызова функции и передаёт ей указатель на эту функцию. А если ты хочешь, чтобы в одной строчке программы сразу объявить как и что она делает и хранит, то ты многого хочешь. Достаточно того, что компилятор из этой строки узнал новую и необходимую для него информацию.
S>Процедурные типы данных и соглашения о вызове метода не имеют ничего общего.
Кто-то утверждал обратное?
Я утверждал лишь то, что тип функции используется компилятором для определения того, как вызывать функцию, в частности, сколько места в стеке и подо что нужно.
FDS>>>>О способе получения — да, так как мы должны вызвать функцию и отвести место, куда будем получать результат (если результат сложный — то место под указатель на результат) S>>>мы должны вызвать функцию, чтобы получить данные обратно. Зачем об этой функции что-то знать компилятору? FDS>>Чтобы её правильно вызвать, как ты понимаешь. S>Правильно вызвать — это одно, а то как хранит процедура переданные ей данные — это другое.
Ты правда такой или притворяешься?
Давай по пунктам, какой из них непонятен.
1. Тип процедуры есть информация — это понятно?
Если да, то
2. Тип процедуры указывает на то, что она процедура, т.е. её надо вызывать и что для вызова используется указатель
Ели это тоже понятно, то
3. Тип аргументов процедуры (т.е. сама сигнатура процедуры, её тип) указывает компилятору, как аргументы хранятся при вызове.
Если это тоже понятно, то
4. Пункты 2 и 3 и есть информация, которую компилятор использует для правильного вызва, который включает хранение в стеке или регистрах аргументов
Если это тоже понятно, то
5. Это и есть та информация о хранении данных, о которой указывает тип процедуры
Если это тоже понятно, то
6. Все остальные данные и информация о них абсолютно пофигу, независимо от того и где они, 5-ый пункт доказывает, что тип функции, как и любой другой тип, указывает компилятору, как хранить некоторую информацию.
Если это понятно, то
7. О том, что он указывает как хранить что-то кроме аргументов функции и указателя на функцию я никогда не утверждал
Здравствуйте, samius, Вы писали:
S>Не понимаю, что имеется в виду под хранением имени и списка параметров.
S>Я имел в виду нечто вроде определений cons ...
Ты имеешь в виду высокоуровневые вещи, а говорят тебе о низкоуровневых — о том как, если бы дело в asm, ты хранил бы параметры.
Т.е. тип процедуры определяет информацию о хранении данных, но, естественно, вовсе не ту, о которой ты говоришь
Так же, скажем, нетипизированный массив объявляет только о том, что данные занимают не более некоего объёма памяти, не говоря ничего об их структуре, но при этом ещё и говорит компилятору, что есть 4 байта на указатель на этот массив — т.е. говорит и о структуре и о размере некоторых других полей.
Здравствуйте, Temoto, Вы писали:
T>Пока это всё, к сожалению, многие светлые умы обходят вопрос стороной.
На самом деле, это не всё.
Главное, что мы выяснили: система типов позволяет организованно определять группы методов и полей, чем существенно облегчает работу программисту, т.к. иначе для кадого объекта программист вынужден был бы при создании этого объекта определять весь набор методов и полей объекта вручную.
Здравствуйте, Temoto, Вы писали:
T>Было мнение, что диспатчить полиморфизм можно и без типов, но это не противоречит второму пункту. Остальное тоже можно делать и в рамках одного типа, но с разветвлённой системой — намного более эффективно.
Ты зря опускаешь именно повышение эффективности — это ведь тоже цель типов.
Кроме этого типы позволяют говорить самому программисту о том, что он собирается получить и тем самым лучше документировать и структурировать программу, т.е. не только компилятору объявляют тип и наследников типа, но и программисту — по сути играют документирующую роль, причём именно формально-документирующую, в отличие от неформальной документации на естественном языке. Это большая разница, других инструментов для формальной документации у нас нет — это важно не только компилятору.
Здравствуйте, FDSC, Вы писали:
FDS>Здравствуйте, samius, Вы писали:
FDS>Информация о типе, хранящаяся в голове программиста — это абстракция. Т.е. у компилятора, получается, системы типов технологически нет, соответственно и функции она никакой в языке не играет.
Я не понимаю, о чем ты. Если даже объекты состоят из словарей полей и методов, то это и есть система типов, которая будет играть определяющую роль в языке и его интерпретации.
Назови уже в конце концов язык без системы типов. Но не абстрактный, который ты придумал, а конкретный, существующий. Я все не могу понять, о чем ты думаешь, когда говоришь об отсутствии системы типов, может быть об Io?
S>>Ну да. В итоге получаем что наличие ассоциации с операцией сложения у двух операндов не обязательно.
FDS>При условии, что определён порядок применения этой операции.
Не обязательно и все тут.
А что ты имеешь под порядком, ассоциативность? Если да, то с какого конца будешь вычислять 1 + 2 + 3 если ассоциативность не определена?