Структурная и номанативная типизация
От: x-code  
Дата: 18.04.11 06:10
Оценка:
Похожая тема уже была здесь
Автор: VladD2
Дата: 06.03.11
, но меня интересует нечто другое.
Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно?
Для примера — вариант в Scala:
class File(name: String) {
  def getName(): String = name
  def open() { /*..*/ }
  def close() { println("close file") }
}
def test(f: { def getName(): String }) { println(f.getName) }

test(new File("test.txt"))
test(new java.io.File("test.txt"))

В Go вроде бы тоже есть нечто подобное, но не нашел примера
А можно сделать еще лучше? При этом (важно!) не ломая классического синтаксиса обычной номинативной типизации ?
Re: Структурная и номанативная типизация
От: night beast СССР  
Дата: 18.04.11 06:35
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Похожая тема уже была здесь
Автор: VladD2
Дата: 06.03.11
, но меня интересует нечто другое.

XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно?
XC>Для примера — вариант в Scala:
XC>
XC>class File(name: String) {
XC>  def getName(): String = name
XC>  def open() { /*..*/ }
XC>  def close() { println("close file") }
XC>}
XC>def test(f: { def getName(): String }) { println(f.getName) }

XC>test(new File("test.txt"))
XC>test(new java.io.File("test.txt"))
XC>


prototype getName {};

def test[getName,...] {
   /*...*/
};
Re: Структурная и номанативная типизация
От: dotneter  
Дата: 18.04.11 06:43
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Похожая тема уже была здесь
Автор: VladD2
Дата: 06.03.11
, но меня интересует нечто другое.

XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно?
XC>Для примера — вариант в Scala:
XC>
XC>class File(name: String) {
XC>  def getName(): String = name
XC>  def open() { /*..*/ }
XC>  def close() { println("close file") }
XC>}
XC>def test(f: { def getName(): String }) { println(f.getName) }

XC>test(new File("test.txt"))
XC>test(new java.io.File("test.txt"))
XC>

XC>В Go вроде бы тоже есть нечто подобное, но не нашел примера
XC>А можно сделать еще лучше? При этом (важно!) не ломая классического синтаксиса обычной номинативной типизации ?

def test(f: auto) { println(f.getName) }
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re: Структурная и номанативная типизация
От: jazzer Россия Skype: enerjazzer
Дата: 18.04.11 06:49
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно?

XC>
XC>def test(f: { def getName(): String }) { println(f.getName) }

XC>


шаблоны в С++:
void test(T f)
{
  BOOST_MPL_ASSERT((is_same< decltype(f.getName()), string >));
  cout << f.getName();
}

это если нужно просто отвалиться по assert в случае неправильного типа.

Если же хочется перегрузки по наличию/отсутствию функции, то нужно будет эту проверку упаковать в enable_if:
template<class T>
auto test(T f) -> typename enable_if<
                    is_same< decltype(f.getName()), string >
                  >::type
{
  cout << f.getName();
}
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Структурная и номанативная типизация
От: x-code  
Дата: 18.04.11 07:17
Оценка: +1
Здравствуйте, jazzer, Вы писали:

J>шаблоны в С++:

J>
J>void test(T f)
J>{
J>  BOOST_MPL_ASSERT((is_same< decltype(f.getName()), string >));
J>  cout << f.getName();
J>}
J>

J>это если нужно просто отвалиться по assert в случае неправильного типа.

J>Если же хочется перегрузки по наличию/отсутствию функции, то нужно будет эту проверку упаковать в enable_if:

J>
J>template<class T>
J>auto test(T f) -> typename enable_if<
J>                    is_same< decltype(f.getName()), string >
                  >>::type
J>{
J>  cout << f.getName();
J>}
J>


Кстати, интерсный пример для иллюстрации цели этой темы. Я программист С++, почти ничего не понял в этом коде при этом на Скале не писал ни строчки кода вообще, а пример вполне понятен.
Re: Структурная и номанативная типизация
От: Temoto  
Дата: 18.04.11 07:20
Оценка:
XC>Похожая тема уже была здесь
Автор: VladD2
Дата: 06.03.11
, но меня интересует нечто другое.

XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно?
XC>Для примера — вариант в Scala:
XC>
XC>class File(name: String) {
XC>  def getName(): String = name
XC>  def open() { /*..*/ }
XC>  def close() { println("close file") }
XC>}
XC>def test(f: { def getName(): String }) { println(f.getName) }

XC>test(new File("test.txt"))
XC>test(new java.io.File("test.txt"))
XC>

XC>В Go вроде бы тоже есть нечто подобное, но не нашел примера

package main

import "fmt"

type File struct {}
func (f File) getName() string {
  return "John"
}

func test(f interface{getName() string}) string {
  return f.getName()
}

func main() {
        var f File
    fmt.Println("Hello", test(f))
}


XC>А можно сделать еще лучше? При этом (важно!) не ломая классического синтаксиса обычной номинативной типизации ?



def test(f: auto) { println(f.getName) }
Re: Структурная и номанативная типизация
От: Sorc17 Россия  
Дата: 18.04.11 07:30
Оценка:
Ни скалы ни С++ не знаю, напишите пример для особо одарённых Java программистов пожалуйста
Для нас [Thompson, Rob Pike, Robert Griesemer] это было просто исследование. Мы собрались вместе и решили, что ненавидим C++ [смех].
Re[3]: Структурная и номанативная типизация
От: jazzer Россия Skype: enerjazzer
Дата: 18.04.11 07:30
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Кстати, интерсный пример для иллюстрации цели этой темы. Я программист С++, почти ничего не понял в этом коде

В "этом коде" — это во втором? Ну так для этого надо быть в теме enable_if (http://www.boost.org/libs/utility/enable_if.html), это да, тут ничего не поделаешь. Но это нужно только если нужна перегрузка — не самый частый случай, обычно просто сообщения об ошибке достаточно, и об этом первый пример.
Надеюсь, в первом-то примере всё понятно, или тоже нет?

XC>при этом на Скале не писал ни строчки кода вообще, а пример вполне понятен.

Ну извини, Скала — только-только появившийся язык (2004 год). Нафиг бы он был нужен, если б не умел что-то делать лучше, чем существующие языки
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Структурная и номанативная типизация
От: x-code  
Дата: 18.04.11 07:38
Оценка:
Здравствуйте, Temoto, Вы писали:

XC>>А можно сделать еще лучше? При этом (важно!) не ломая классического синтаксиса обычной номинативной типизации ?


T>def test(f: auto) { println(f.getName) }

Т.е. просто положиться на вывод типов?

И кстати, еще интересный вопрос: какой тип должен использоваться реально для структурной типизации? Специальный "структурный" интерфейс? Как он должен быть устроен на низком уровне?
И как сделать, чтобы в программе отличались "структурные" интерфейсы от "номинативных" (при условии, что в некоторых случаях "номинативные" тоже нужны)?
Re[3]: Структурная и номанативная типизация
От: Temoto  
Дата: 18.04.11 08:23
Оценка:
XC>>>А можно сделать еще лучше? При этом (важно!) не ломая классического синтаксиса обычной номинативной типизации ?

T>>def test(f: auto) { println(f.getName) }

XC>Т.е. просто положиться на вывод типов?

Да. Строго говоря, это скорее будет вывод интерфейса.

XC>И кстати, еще интересный вопрос: какой тип должен использоваться реально для структурной типизации? Специальный "структурный" интерфейс? Как он должен быть устроен на низком уровне?


Да. Специальный анонимный интерфейс для каждого использования объекта.

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

interface test_f_1f8sbdddx {
  getName() : string
}

def test(f: test_f_1f8sbdddx) { println(f.getName) }


XC>И как сделать, чтобы в программе отличались "структурные" интерфейсы от "номинативных" (при условии, что в некоторых случаях "номинативные" тоже нужны)?


Не вижу никаких причин, хотеть чтобы структурные интерфейсы отличались от номинативных. У них всё равно будут отличия: 1) номинативные интерфейсы нужно сначала объявить, 2) следовательно у них есть имя. Но зачем делать ещё какие-то отличия?
Re[4]: Структурная и номанативная типизация
От: x-code  
Дата: 18.04.11 09:01
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Не вижу никаких причин, чтобы этот интерфейс был на низком уровне устроен иначе, чем другие интерфейсы. Фактически, код выше можно переписать на этапе проверки типов в


T>
T>interface test_f_1f8sbdddx {
T>  getName() : string
T>}

T>def test(f: test_f_1f8sbdddx) { println(f.getName) }
T>

И как заставить все используемые там классы наследоваться от этого интерфейса (на низком уровне)? Особенно если многие классы уже в библиотеках в каком-то двоичном виде?

T>Не вижу никаких причин, хотеть чтобы структурные интерфейсы отличались от номинативных. У них всё равно будут отличия: 1) номинативные интерфейсы нужно сначала объявить, 2) следовательно у них есть имя. Но зачем делать ещё какие-то отличия?

Если я например имею именованный интерфейс, но хочу чтобы он был структурным.
Re[5]: Структурная и номанативная типизация
От: Temoto  
Дата: 18.04.11 09:38
Оценка:
T>>Не вижу никаких причин, чтобы этот интерфейс был на низком уровне устроен иначе, чем другие интерфейсы. Фактически, код выше можно переписать на этапе проверки типов в

T>>
T>>interface test_f_1f8sbdddx {
T>>  getName() : string
T>>}

T>>def test(f: test_f_1f8sbdddx) { println(f.getName) }
T>>

XC>И как заставить все используемые там классы наследоваться от этого интерфейса (на низком уровне)? Особенно если многие классы уже в библиотеках в каком-то двоичном виде?

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

Наверное, сразу стоило сказать вслух. Я неявно подразумеваю вот что: номинативная типизация это структурная с дополнительными ограничениями (явное указание конкретного интерфейса). Логическим следствием было бы реализовывать в компиляторе только структурную типизацию. И сверху сахаром [никому не нужную] номинативную, которая только вводит дополнительное ограничение к тому что работает.

Вот пример как именно можно выразить номинативный интерфейс:

В коде написано:
interface IFile {
  read() : bytes
  write(bytes)
  close()
}

f : IFile = open(...)
f.close()


Компилятор преобразует в:
f : interface <
  const _InterfaceName = "IFile"
  close()
> = open(...)
f.close()


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

T>>Не вижу никаких причин, хотеть чтобы структурные интерфейсы отличались от номинативных. У них всё равно будут отличия: 1) номинативные интерфейсы нужно сначала объявить, 2) следовательно у них есть имя. Но зачем делать ещё какие-то отличия?

XC>Если я например имею именованный интерфейс, но хочу чтобы он был структурным.

Сделано. Любой именованый интерфейс является структурным. Аналогия: любая именованая функция является функцией (лямбдой).
Re: Структурная и номанативная типизация
От: z00n  
Дата: 18.04.11 11:37
Оценка: 34 (1)
Здравствуйте, x-code, Вы писали:

XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно?


Структурные типы (и вывод типов) есть в Haxe:
http://haxe.org/manual/2_types
http://haxe.org/ref/type_advanced

var p : { x : Int, y : Int }; // declare a typed variable
p = { x : -1, y : 65 }; // OK
p = { x : -1 }; // ERROR : field y is missing
Re: Структурная и номанативная типизация
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.04.11 15:58
Оценка:
Здравствуйте, x-code, Вы писали:

XC>В Go вроде бы тоже есть нечто подобное, но не нашел примера


В Go не поддерживается номинативная система типов. Там только структурная.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Структурная и номанативная типизация
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.04.11 16:11
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования?


Возможно. Например, в F# записи подчиняются законам структурной типизации принятой в ML, а все остальные типы подчиняются правилам номинативной системы типов.

У меня лично возникают два вопроса по этому поводу:
1. Зачем нужна номинативная типизация в языке где качественно поддерживается структурная?
2. Как эффективно реализовать структурную типизацию в рантаймах на это не рассчитанных (.Net/Mono/Java)? Дело в том, что в этих рантаймах нет нужных средств и в лучшем случае получится эмуляция. А это повлечет или сильные ограничения, или потерю производительности.

Что же касается того как совмещать структурную и номинативную типизации, то тут есть только одно решение, на мой взгляд — разделить типы в языке на те что подчиняются структурной типизации и остальные. Но тут есть нюансы:
1. Ограничить структурную типизацию только этими типами. Так сделано, например, с записями в F#.
2. Дать возможность любой тип приводить к структурному.

Для второго случая я бы ввел некий модификатор для интерфейсов (если оные есть в языке). Например:
structural interface ITest
{
  ...
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Структурная и номанативная типизация
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.04.11 16:26
Оценка:
Здравствуйте, x-code, Вы писали:

XC>И как заставить все используемые там классы наследоваться от этого интерфейса (на низком уровне)? Особенно если многие классы уже в библиотеках в каком-то двоичном виде?


Если язык поддерживает КОП (компонентно-ориентированное программирование), то никак или с серьезным рантайм-верехэдом.
Например, в языке где поддерживаются ссылки на методы объектов можно превратить такой интерфейс с структуру содержащую ссылки на методы. Таким образом код вида (базовый языком взят C#):
interface ITest
{
  int Method1(string s);
  string Prop1 { get; }
}

class A
{
  public Test(structural ITest test)
  {
    var x = test.Method1(test.Prop1);
    ...
  }
}
...
new A().Test(new B());

можно переписать в:
class ITest_Proxy
{
  public Func<string, int> Method1;
  public Func<string>      Prop1;
}

class A
{
  public Test(ITest test)
  {
    var x = test.Method1(test.Prop1);
    ...
  }
}
...
var tempB = new B();
var proxy = new ITest_Proxy() { tempB.Method1; tempB.Prop1; `}
new A().Test(proxy);

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

T>>Не вижу никаких причин, хотеть чтобы структурные интерфейсы отличались от номинативных. У них всё равно будут отличия: 1) номинативные интерфейсы нужно сначала объявить, 2) следовательно у них есть имя. Но зачем делать ещё какие-то отличия?

XC>Если я например имею именованный интерфейс, но хочу чтобы он был структурным.

Это не проблема. Как в примере выше можно указывать требование структурной совместимости в параметре или переменной/поле. Ну, а для функций принимающих структурные интерфейсы можно можно просто генерировать два тела. Одно для структурного прокси, а другое для обычной реализации. Правда если таких параметров много, то может начаться комбинаторный взрыв и придется генерировать не столько тел, сколько имеется пересечений структурных интерфейсов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Структурная и номанативная типизация
От: jazzer Россия Skype: enerjazzer
Дата: 18.04.11 17:40
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Если я например имею именованный интерфейс, но хочу чтобы он был структурным.


Ну в моем примере на С++ это будет просто набор условий типа того, что уже там есть, объединенный в именованную структуру, которая будет использоваться в коде вместо is_same.

Т.е. будет нечто вроде:
template<class T>
auto MyInterface(T f)
  -> and_<
       is_same< decltype(f.getName()), string >,
       is_same< decltype(f.setName(string)), void >,
       // и т.д., остальные условия
     >::type;

and_<...>::type вернет либо true_, либо false_ (это типы).

Теперь у тебя есть структурный интерфейс с именем MyInterface.
Дальше в пользовательском коде:
template<class T>
void test(T f)
{
  BOOST_MPL_ASSERT((is_same< decltype(MyInterface(f)), true_ >));
  cout << f.getName();
}

Естественно, с помощью элементарного макроса это сводится к
#define CHECK_IFACE(iface) BOOST_MPL_ASSERT((is_same< decltype(iface), true_ >))

template<class T>
void test(T f)
{
  CHECK_IFACE(MyInterface(f));
  cout << f.getName();
}

Аналогично для перегрузок
#define CHECK_IFACE_RET(iface) typename enable_if< is_same< decltype(iface), true_ > >::type

template<class T>
auto test(T f) -> CHECK_IFACE_RET(MyInterface(f))
{
  cout << f.getName();
}


Надеюсь, с макросами тебя это уже не пугает?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: Структурная и номанативная типизация
От: x-code  
Дата: 19.04.11 06:06
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Надеюсь, с макросами тебя это уже не пугает?

Пугает то, то что С++ — прямой наследник Си — уходит все дальше и дальше в какие-то дебри, а языки для всяких безопасных тормозных фреймворков становятся все лучше и лучше И где в мире справедливость?
Хотя, надо признать, реализация структурной типизации на шаблонах самая быстрая их всех возможных — для каждого варианта использования будет сгенерирована своя версия функции.
Re[2]: Структурная и номанативная типизация
От: x-code  
Дата: 19.04.11 06:17
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>У меня лично возникают два вопроса по этому поводу:

VD>1. Зачем нужна номинативная типизация в языке где качественно поддерживается структурная?
Не могу строго аргументировать, но кажется, что номинативная "привычнее", естественнее и проще в реализации, и в большинстве случаев ее достаточно.

VD>Что же касается того как совмещать структурную и номинативную типизации, то тут есть только одно решение, на мой взгляд — разделить типы в языке на те что подчиняются структурной типизации и остальные. Но тут есть нюансы:

VD>1. Ограничить структурную типизацию только этими типами. Так сделано, например, с записями в F#.
VD>2. Дать возможность любой тип приводить к структурному.

Да, похоже что так можно, хотя сразу понятно что там огромное количество неочевидных нюансов
Re[7]: Структурная и номанативная типизация
От: jazzer Россия Skype: enerjazzer
Дата: 19.04.11 06:31
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Здравствуйте, jazzer, Вы писали:


J>>Надеюсь, с макросами тебя это уже не пугает?

XC>Пугает то, то что С++ — прямой наследник Си — уходит все дальше и дальше в какие-то дебри, а языки для всяких безопасных тормозных фреймворков становятся все лучше и лучше И где в мире справедливость?
Да ладно тебе, какие же это дебри — автоматический вывод типов, переменное число аргументов у макросов и шаблонов, универсальная инициализация и прочие вкусности? Это все, имхо, делает язык лучше. Т.е. С++0х, имхо, однозначно лучше С++98.
А если не рассматривать С++0х, то в дебри уходят программисты, а не язык Буст, Александреску, шаблонное и препроцессорное метарограммирование — это все реализовано на базе старого доброго С++98

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

Да, все эти игры с типизацией в С++ остаются на стадии компиляции, а после того, как сгенерены и проверены все типы, идет обычная кодогенерация сишного уровня, со всеми подобающими оптимизациями, специфическими для результирующего типа. Т.е. сколько бы я проверок не навернул во время компиляции, если компилятор не кривой, они никакого влияния на скорость исполнения скомпилированного кода не окажут.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.