Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
Статически типизированные языки, по определению, проверяют типы в время компиляции , не время выполнения . Одна из очевидных проблем с системой, описанной выше, - то, что компилятор собирается проверить типы, когда программа компилируется, не во время выполнения.
Теперь, Вы могли встроить больше аналитики в компилятор, таким образом, это могло происходить , типы, вместо того, чтобы иметь программиста явно объявляют типы; компилятор смог видеть, что MyClass
реализации MyMethod()
метод, и обрабатывает этот случай соответственно, без потребность явно объявить интерфейсы (как Вы предполагаете). Такой компилятор мог использовать вывод типа, такой как Хиндли-Milner .
, Конечно, некоторые статически типизированные языки как Haskell уже делают что-то подобный к тому, что Вы предлагаете; компилятор Haskell может вывести типы (большую часть времени) без потребности явно объявить их. Но очевидно, Java/C# не имеют этой способности.
Походит на Mixins или Черты:
http://en.wikipedia.org/wiki/Mixin
http://www.iam.unibe.ch/~scg/Archive/Papers/Scha03aTraits.pdf
Предрелизный дизайн для Visual Basic 9 имел поддержку статического утиного ввода с помощью динамических интерфейсов, но они сокращают функцию * для поставки вовремя.
F# поддерживает статический утиный ввод, хотя с выгодой: необходимо использовать членские ограничения. Детали доступны в этом запись в блоге .
Пример из процитированного блога:
let inline speak (a: ^a) =
let x = (^a : (member speak: unit -> string) (a))
printfn "It said: %s" x
let y = (^a : (member talk: unit -> string) (a))
printfn "Then it said %s" y
type duck() =
member x.speak() = "quack"
member x.talk() = "quackity quack"
type dog() =
member x.speak() = "woof"
member x.talk() = "arrrr"
let x = new duck()
let y = new dog()
speak x
speak y
Я не вижу точку. Почему бы не явный, что класс реализует интерфейс и сделал с ним? Реализация интерфейса - то, что говорит другим программистам, что этот класс, как предполагается, ведет себя в способе, которым определяет интерфейс. Просто наличие того же имени и подписи на методе не передает гарантий, что намерение разработчика состояло в том, чтобы выполнить подобные действия с методом. Это может быть, но почему оставляют на виду его для интерпретации (и неправильное употребление)?
причина можно "уйти" с этим успешно на динамических языках, больше имеет отношение к TDD, чем с самим языком. По-моему, если язык предлагает средство для предоставления этих видов руководства другим, которые используют/просматривают код, необходимо использовать его. Это на самом деле улучшает ясность и стоит несколько дополнительных символов. В случае, где у Вас нет доступа, чтобы сделать это, затем Адаптер служит той же цели явного объявления, как интерфейс касается другого класса.
Как насчет того, чтобы использовать шаблоны в C++?
class IMyInterface // Inheritance from this is optional
{
public:
virtual void MyMethod() = 0;
}
class MyClass // Does not explicitly implement IMyInterface
{
public:
void MyMethod() // But contains a compatible method definition
{
std::cout << "Hello, world!" "\n";
}
}
template<typename MyInterface>
void CallMyMethod(MyInterface& m)
{
m.MyMethod(); // instantiation succeeds iff MyInterface has MyMethod
}
MyClass obj;
CallMyMethod(obj); // Automatically generate code with MyClass as
// MyInterface
я на самом деле не скомпилировал этот код, но я полагаю, что это является осуществимым и довольно тривиальный C ++-ization предложенного оригинала (но нерабочим), код.
Шиканье определенно является статическим утиным типизированным языком: http://boo.codehaus.org/Duck+Typing
выборка:
Шиканье является статически типизированным языком, как Java или C#. Это означает, что Ваши приложения шиканья будут работать о с такой скоростью, как кодированные на других статически типизированных языках для.NET или Моно. Но использование статически типизированного языка иногда ограничивает Вас к негибкому и подробному стилю кодирования с иногда необходимыми описаниями типа (как "x как интервал", но это не часто необходимо из-за Вывода типа шиканья), и иногда необходимые броски типа (см. Типы Кастинга). Поддержка шиканья Вывода типа и в конечном счете дженериков помогает здесь, но...
Иногда уместно бросить систему поддержки, обеспеченную статическим контролем типов. Возможно, Вы просто хотите исследовать API, не волнуясь слишком много о сигнатурах методов, или возможно Вы создаете код, который говорит с внешними компонентами, такими как COM-объекты. Так или иначе выбор должен быть Вашим не мой.
Наряду с нормальными типами как объект, интервал, строка... шикает, имеет специальный тип, названный "уткой". Термин вдохновлен утиной функцией ввода рубинового языка программирования ("Если это идет как утка и шарлатаны как утка, это должна быть утка").
Большинство языков в семействе ML поддерживают структурные типы с логическим выводом и схемы ограниченного типа , что является терминологией компьютерного разработчика языка, которая кажется наиболее вероятной тем, что вы имеете в виду под фраза «статическая утиная типизация» в исходном вопросе.
Наиболее популярные языки этого семейства, которые приходят на ум, включают: Haskell, Objective Caml, F # и Scala. Тот, который больше всего соответствует вашему примеру, конечно, будет Objective Caml. Вот перевод вашего примера:
open Printf
class type iMyInterface = object
method myMethod: unit
end
class myClass = object
method myMethod = printf "Hello, world!"
end
let callMyMethod: #iMyInterface -> unit = fun m -> m#myMethod
let myClass = new myClass
callMyMethod myClass
Примечание: некоторые использованные вами имена должны быть изменены, чтобы соответствовать понятию OCaml о семантике регистра идентификаторов, но в остальном это довольно простой перевод.
Также стоит отметить, ни аннотация типа в функции callMyMethod
, ни определение типа класса iMyInterface
строго не требуется. Objective Caml может вывести все в вашем примере вообще без каких-либо объявлений типов.
Совершенно новый ответ на этот вопрос, Go имеет именно эту функцию . Я думаю, что это действительно круто и умно (хотя мне будет интересно посмотреть, как это проявляется в реальной жизни), и спасибо за то, что я думаю об этом.
Как описано в официальной документации (как часть Турне по Вперед, с примером кода) :
Интерфейсы реализуются неявно
Тип реализует интерфейс, реализуя свои методы. Есть нет явного объявления намерения, нет ключевого слова «реализует».
Неявные интерфейсы отделяют определение интерфейса от его реализация, которая затем может появиться в любом пакете без предварительная договоренность.
В последней версии моего языка программирования Heron он поддерживает нечто подобное через конструктивно-субтипирующий оператор принуждения, называемый как
. Так что вместо:
MyClass obj = new MyClass();
CallMyMethod(obj);
Вы бы написали:
MyClass obj = new MyClass();
CallMyMethod(obj as IMyInterface);
Как и в Вашем примере, в данном случае MyClass
не должен явно реализовывать IMyInterface
, но если бы это произошло, то кастинг мог бы происходить неявно и оператор как
мог бы быть опущен.
Немного больше о технике, которую я называю явным структурным подтипированием, я написал в этой статье .
.