Новая функция в Ceylon 1.1, о которой я раньше не писал, — это динамические интерфейсы . Это было то, над чем мы с Энрике работали вместе с Корбин Уселтон, одним из наших студентов GSoC.
Обычно, когда мы взаимодействуем с объектами JavaScript, мы делаем это из dynamic
блока, где обычная скрупулезная проверка типов в Цейлоне подавляется. Проблема с этим подходом состоит в том, что, если это API, которым я пользуюсь регулярно, моя IDE не может помочь мне запомнить имена и подписи всех операций API.
Динамические интерфейсы позволяют приписывать статические типы нетипизированному API-интерфейсу JavaScript. Например, мы могли бы написать динамический интерфейс для HTML 5 CanvasRenderingContext2D
следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
dynamic CanvasRenderingContext2D { shared formal variable String|CanvasGradient|CanvasPattern fillStyle; shared formal variable String font; shared formal void beginPath(); shared formal void closePath(); shared formal void moveTo(Integer x, Integer y); shared formal void lineTo(Integer x, Integer y); shared formal void fill(); shared formal void stroke(); shared formal void fillText(String text, Integer x, Integer y, Integer maxWidth=- 1 ); shared formal void arc(Integer x, Integer y, Integer radius, Float startAngle, Float endAngle, Boolean anticlockwise); shared formal void arcTo(Integer x1, Integer y1, Integer x2, Float y2, Integer radius); shared formal void bezierCurveTo(Integer cp1x, Integer cp1y, Integer cp2x, Float cp2y, Integer x, Integer y); shared formal void strokeRect(Integer x, Integer y, Integer width, Integer height); shared formal void fillRect(Integer x, Integer y, Integer width, Integer height); shared formal void clearRect(Integer x, Integer y, Integer width, Integer height); shared formal CanvasGradient createLinearGradient(Integer x0, Integer y0, Integer x1, Integer y1); shared formal CanvasGradient createRadialGradient(Integer x0, Integer y0, Integer r0, Integer x1, Integer y1, Integer r1); shared formal CanvasPattern createPattern(dynamic image, String repetition); //TODO: more operations!! } dynamic CanvasGradient { shared formal void addColorStop(Integer offset, String color); } dynamic CanvasPattern { //todo } |
Теперь, если мы назначим экземпляр JavaScript CanvasRenderingContext2D
этому типу интерфейса, нам не нужно находиться внутри dynamic
блока при вызове его методов. Вы можете попробовать его в своем браузере, нажав кнопку «ПОПРОБУЙТЕ ОНЛАЙН»!
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
CanvasRenderingContext2D ctx; dynamic { //get the CanvasRenderingContext2D from the //canvas element using dynamically typed code ctx = ... ; } //typesafe code, checked at compile time ctx.fillStyle = "navy" ; ctx.fillRect( 50 , 50 , 235 , 60 ); ctx.beginPath(); ctx.moveTo( 100 , 50 ); ctx.lineTo( 60 , 5 ); ctx.lineTo( 75 , 75 ); ctx.fill(); ctx.fillStyle = "orange" ; ctx.font = "40px PT Sans" ; ctx.fillText( "Hello world!" , 60 , 95 ); |
Обратите внимание, что нам не нужно присваивать явный тип каждой операции интерфейса. Мы можем оставить некоторые методы или даже просто некоторые параметры метода нетипизированными, объявив их dynamic
. Однако такие операции могут вызываться только из dynamic
блока.
Предостережение: динамические интерфейсы — удобная фикция. Они могут упростить работу с API в вашей IDE, но во время выполнения Ceylon ничего не может сделать, чтобы гарантировать, что объект, который вы назначаете типу динамического интерфейса, действительно реализует операции, которые вы ему приписали.
Ссылка: | Typesafe API для браузера от нашего партнера JCG Гэвина Кинга в блоге команды Ceylon Team . |