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

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

public class Lion
{
  public void Roar() { Console.WriteLine("Aaarrgghh");}
} 

public static Main(string[] args)
{
  object myCat = new object(); // just plain object, no type!
  // adding a Roar() method to the myCat instance 
  myCat.Roar += delegate() {Console.WriteLine("Miauew");}
  // At this point myCat should qualify to be a Lion.
  // So we should be able to successfully duck-type-cast 
  // her to a lion
  Lion myLion = myCat as Lion;
  // now the myLion reference is strongly typed, 
  // so I expect the Intellisense window pop up 
  // and offer me the Roar() method when I hit the dot after "myLion"
  myLion.Roar();
}

Я хочу, чтобы эта программа компилировалась без ошибок, запускалась без исключений и печатала "Miauew" в консоли. Есть ли язык, который может это сделать? Может С# 4.0?


person Mr. Lame    schedule 28.06.2009    source источник
comment
Я думал о чем-то подобном как о расширении Lua. Я использую Lua во встроенной среде, где ценен каждый байт памяти. Lua также использует хеш-таблицы внутри, что очень неэффективно с точки зрения памяти для определенных типов объектов. Было бы неплохо иметь структурный синтаксис для простого создания плотно упакованного объекта в Lua, вместо того, чтобы полагаться на пользовательские объекты в C.   -  person Dolphin    schedule 28.06.2009


Ответы (5)


Возможно, новый динамический тип в C# 4.0. посмотрите на это: http://blogs.msdn.com/cburrows/archive/2008/10/27/c-dynamic.aspx

person Emiswelt    schedule 28.06.2009
comment
После прочтения о C# 4.0 кажется, что этот динамический тип просто позволяет вам отложить привязку типа к среде выполнения, но не позволяет вам добавлять новый член экземпляров объекта во время выполнения, как это делает Python или JS. - person Mr. Lame; 28.06.2009
comment
Оно делает. Новый тип BCL ExpandoObject делает именно это без дополнительной работы с вашей стороны. Вы также можете стать намного более изощренным, по существу создав свой собственный связыватель времени выполнения. - person Curt Hagenlocher; 05.07.2009

Это скорее зависит от того, что вы намеревались реализовать с помощью типа Lion, не виртуальный метод.

Расширенная типизация (набор объектов данного типа — это те, которые обладают свойствами типа, что близко к статическому эквиваленту утиной печати) требует, чтобы структура объекта подразумевала его тип, но ваш Lion type не имеет структуры - он только говорит, что все, что является львом, имеет этот конкретный метод Roar. Итак, для вашего примера я не вижу способа, которым вы могли бы превратить свою кошку в Льва, поскольку у нее нет единственного структурного свойства, которое, как вы сказали, есть у львов.

Если, с другой стороны, вы имели в виду, говоря, что все, что вы называете львом, может иметь либо собственный метод рыка, либо будет использовать метод в льве, это ничего не говорит о типе объектов, которые являются львами, и AFAIK вы могли бы получить такое же поведение с методом расширения для объекта (хотя я недостаточно знаю С#, чтобы знать, переопределяют ли собственные методы методы расширения в С#).

В динамической IDE нет причин, по которым вам нужно приводить к Lion, прежде чем IDE сможет определить, что у myCat есть свойство Roar — эта информация выводится статически.

Причина, по которой поддержка IDE затруднена в языках с динамически конструируемыми типами, таких как JavaScript, заключается в том, что вы можете сделать это:

let myCat = {}

if ( locale.name == 'en' )
    myCat.roar = function () { alert ( "Miauew" ); }
else
    mCat[ resources.getString( 'roar' ) ] = 
        function () { alert ( resources.getString ( 'Miauew' ) ); }


// the structure of the type of myCat depends what locale the code
// is running in, so you can't deduce the Intellisense
myCat.

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

Если Intellisense не может вывести структуру объектов, структура которых выводима статически, то это недостаток Intellisense, а не динамической типизации.

Что бы вы назвали преимуществом строгой типизации в вашем примере?

person Pete Kirkham    schedule 28.06.2009
comment
В C# методы расширения — это просто синтаксический сахар для вызова статического метода для некоторого класса в пространстве имен. Они существуют только для того, чтобы превратить уродливые ObjectExtensions.DoSomething(new Object()) в new Object().DoSomething() - person rpetrich; 28.06.2009
comment
Преимущество строгой типизации: мне особенно нравится intellisense. Это невозможно пропустить в гигантских проектах. Ошибки компилятора — это хорошо, но я могу жить без них. - person Mr. Lame; 28.06.2009
comment
В приведенном вами коде для Intellisense достаточно вывода структурного типа. Вам не нужна строгая типизация; на самом деле, в строго типизированном языке вам придется полагаться на вывод, поскольку вы не можете выполнять приведение типов в строго типизированных языках. - person Pete Kirkham; 28.06.2009
comment
И есть ли такой язык, который позволяет мне указывать классы, которые допускают интеллектуальное И слабо типизированное, как JS? Потому что классы в JS — это просто доработка. - person Mr. Lame; 29.06.2009
comment
В Smalltalk есть как классы, так и динамическая типизация, как и в Ruby и Python. IDE Smalltalk уже давно имеют автодополнение с учетом типа, я полагаю, что некоторые IDE Ruby, JavaScript и Python имеют автозаполнение с учетом типа. Intellisense — это функция IDE, а не функция языка. - person Pete Kirkham; 29.06.2009

Каждый раз, когда я пытался спланировать что-то подобное, проблема заключалась в актерском составе. Конечно, вы можете просто поверить программисту на слово, но это сочетает в себе худшие черты обеих систем типизации. Возможно, приведение могло бы проверять во время выполнения, реализует ли объект интерфейс Lion, но это в принципе невозможно. В данном случае это выглядит правдоподобно, поскольку все, что вам нужно, — это существование функции void (*)(). Но вообще, что, если у Lion есть метод getHabitat, который возвращает объект, который должен принадлежать другому интерфейсу? Строго типизированный язык должен быть в состоянии сказать наверняка, что он действительно это делает, но без фактического вызова метода вы не можете вообще сказать, возвращает ли нетипизированный код Habitat, и, следовательно, в терминах строгой типизации вы не можете работать. вне ли это Лев.

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

person Community    schedule 28.06.2009
comment
В Javascript вы можете просто вызвать метод по своему усмотрению. Если его там нет, вы получите исключение во время выполнения. Почему компилятор не может просто поверить мне на слово, что это Lion, и вызов метода просто сработает. Если я ошибаюсь, конечно, я получаю исключение во время выполнения, как и в JS. - person Mr. Lame; 28.06.2009
comment
Если компилятор поверит вам на слово, то проверки во время выполнения не будет — он вызовет Lion.Roar() без лишних слов. Но вы хотите, чтобы проверка во время выполнения, как в JS, и myCat.Roar() делали что-то еще. Что это? - person Pete Kirkham; 28.06.2009
comment
Среде выполнения не нужно проверять, когда кастинг выполнен. Фактически, я ожидаю, что приведение будет только синтаксическим сахаром времени разработки. Внизу я просто ожидаю, что он будет работать как JS. Так что делайте проверку при вызове метода. И проверяйте наличие только этого метода, об остальных можете не беспокоиться. Таким образом, приведение не имеет никакого значения во время выполнения, поскольку все объекты являются просто хеш-таблицами JS, они помогают программисту только во время разработки. - person Mr. Lame; 29.06.2009

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

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

Статические типы в динамических языках

Проблема возникает, когда вы смотрите на то, как объекты используются в языках сценариев — все они имеют утиный тип. Это означает, что имя типа (номинальное написание) бесполезно. Все современные императивные языки (Java, C#, C++, C) используют номинальные системы типов. Таким образом, в C++ вы можете сказать, что ожидаете Duck, но в Python вам действительно нужно что-то, что идет quack().

Поэтому рассмотрите возможность добавления статической типизации к языку с утиной типизацией. Поскольку функция ожидает от параметра значение quack(), но не может сказать, что ожидает значение Duck, объединение этих двух параметров затруднено. Вы можете определить интерфейс с именем quacks, который может quack(), и использовать его в качестве типа. Но на самом деле это немного многословно, что убивает преимущества динамической типизации. Однако, возможно, может быть что-то в этом роде (какая-то система структурных типов), которая может сделай это.

Альтернативой было бы просто потребовать от программиста указать Duck, и в любом случае, черт бы побрал этот бизнес с утиным набором — никто на самом деле не использует его, не так ли? Но тогда вы просто пишете Java на Python, и как человек, который пробовал это однажды, позвольте мне сказать вам, что это очень контрпродуктивно.

Динамические типы в статических языках

Итак, давайте посмотрим на это с другой стороны. Как C# выиграет от ключевого слова dynamic? Простой ответ: не будет. Честно говоря, я не вижу той красоты и свободы, которые вы получаете от Python в dynamic C#. Теперь, единственное, что я знаю об этом, исходит из выступления Джона Скита, но ошеломляющее впечатление, которое я получил, состоит в том, что это многословно и неэлегантно. И я думаю, что это не ошибка реализации со стороны C#. Я думаю, это потому, что проблемы, которые динамическая типизация решает в Python, уже решены в C# (хотя и подробно), и dynamic просто ничего не приносит на вечеринку.

Исследование статических/динамических вещей

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

person Paul Biggar    schedule 02.09.2009

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

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

person thSoft    schedule 12.08.2011