Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1d71c75

Browse files
committed
minor update
1 parentf4e4e0c commit1d71c75

File tree

3 files changed

+75
-29
lines changed

3 files changed

+75
-29
lines changed

‎papers/icwe14/icwe14.pdf‎

12.6 KB
Binary file not shown.

‎papers/icwe14/icwe14.tex‎

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
\maketitle
7171

7272
\begin{abstract}
73-
73+
Encoding dynamically typed APIs in statically typed languages can be challenging. We present new ways to encode them in order to preserve type safety and to keep the same expression power.
7474
\end{abstract}
7575

7676
\section{Introduction}
@@ -126,7 +126,8 @@ \subsection{The browser API and its integration in statically typed languages}
126126
\end{lstlisting}
127127
\end{figure}
128128

129-
The case of \jscode{target.addEventListener(name, listener)} is a bit different. The \jscode{name} parameter defines the event to listen to and the \jscode{listener} parameter the function to call back each time such an event occurs. Instead of being polymorphic in its return type, it is polymorphic in its \jscode{listener} parameter. Nevertheless, a similar property as above holds: there is exactly one possible type for the \jscode{listener} parameter for each value of the \jscode{name} parameter. For instance, a listener of \jscode{'click'} events is a function taking a \jscode{MouseEvent} parameter, a listener of \jscode{'keydown'} events is a function taking a \jscode{KeyboardEvent} parameter, and so on. The same pattern as above (defining a set of functions fixing the \jscode{name} parameter value) can be used to encode this function in a statically typed language, but an alternative encoding could be to define one function taking one parameter carrying both the information of the event name and the event listener. Listing~\ref{lst-add-event-listener-one-param} shows such an encoding in Java.
129+
The case of\jscode{target.addEventListener(name, listener)} is a bit different. The\jscode{name} parameter defines the event to listen to and the\jscode{listener} parameter the function to call back each time such an event occurs. Instead of being polymorphic in its return type, it is polymorphic in its\jscode{listener} parameter. Nevertheless, a similar property as above holds: there is exactly one possible type for the\jscode{listener} parameter for each value of the\jscode{name} parameter. For instance, a listener of\jscode{'click'} events is a function taking a\jscode{MouseEvent} parameter, a listener of\jscode{'keydown'} events is a function taking a\jscode{KeyboardEvent} parameter, and so on. The same pattern as above (defining a set of functions fixing the\jscode{name} parameter value) can be used to encode this function in a statically typed language, but an alternative encoding could be to define one function taking one parameter carrying both the information of the event name and the
130+
event listener. Listing~\ref{lst-add-event-listener-one-param} shows such an encoding in Java.
130131

131132
\begin{figure}
132133
\begin{lstlisting}[label=lst-add-event-listener-one-param,language=Java,caption={Encoding of the \jscode{target.addEventListener(name, listener)} function in Java using one paremeter carrying both the information of the event name and the event listener}]
@@ -227,7 +228,7 @@ \subsection{Parametric Polymorphism}
227228
\item Use type\scalacode{U} instead of type\scalacode{T}
228229
\end{enumerate}
229230

230-
Listing~\ref{lst-generics-dom} shows this approach applied to the\jscode{createElement} function: we created a type\scalacode{ElementName<E>}, the\scalacode{name} parameter is not a\scalacode{String} but a\scalacode{ElementName<E>}, and the function returns an\scalacode{E} instead of an\scalacode{Element}. The\scalacode{ElementName<E>} type encodes the relationship between the name of an element and the type of this element. For instance, we created a value\scalacode{Input} of type\scalacode{ElementName<InputElement>}. The last two lines shows how this API is used by end developers: by passing the\scalacode{Input} value as parameter to the function, it fixes the type parameter\scalacode{E} to\scalacode{InputElement} so the returned value has the most possible precise type.
231+
Listing~\ref{lst-generics-dom} shows this approach applied to the\jscode{createElement} function: we created a type\scalacode{ElementName<E>}, the\scalacode{name} parameter is not a\scalacode{String} but a\scalacode{ElementName<E>}, and the function returns an\scalacode{E} instead of an\scalacode{Element}. The\scalacode{ElementName<E>} type encodes the relationship between the name of an element and the type of this element\footnote{The type parameter\scalacode{E} is also called a\emph{phantom type}~\cite{leijen1999domain} because\scalacode{ElementName} values never hold a\scalacode{E} value}. For instance, we created a value\scalacode{Input} of type\scalacode{ElementName<InputElement>}. The last two lines shows how this API is used by end developers: by passing the\scalacode{Input} value as parameter to the function, it fixes the type parameter\scalacode{E} to\scalacode{InputElement} so the returned value has the most possible precise type.
231232

232233
\begin{figure}
233234
\begin{lstlisting}[label=lst-generics-dom,language=java]
@@ -264,62 +265,94 @@ \subsection{Parametric Polymorphism}
264265
\end{lstlisting}
265266
\end{figure}
266267

268+
269+
We show that our encodings support the challenging functions defined in listings\ref{lst-js-comb} and\ref{lst-js-react}.
270+
271+
Listing\ref{lst-generics-comb} and\ref{lst-generics-react} show how these functions can be implemented. They are basically a direct translation from JavaScript to Java.
272+
273+
\begin{figure}
274+
\begin{lstlisting}[label=lst-generics-comb,language=java]
275+
<A, B> void createAndListenTo(
276+
ElementName<A> tagName,
277+
EventName<B> eventName,
278+
Function2<A, B, Void> listener) {
279+
A element = document.createElement(tagName);
280+
element.addEventListener(eventName, event -> listener.apply(event, element));
281+
}
282+
\end{lstlisting}
283+
\end{figure}
284+
285+
\begin{figure}
286+
\begin{lstlisting}[label=lst-generics-react,language=java]
287+
<A> Function<Function<A, Void>, Void> observe(EventTarget target, EventName<A> name) {
288+
return listener -> {
289+
target.addEventListener(name, listener);
290+
}
291+
}
292+
\end{lstlisting}
293+
\end{figure}
294+
295+
Our encoding makes it possible to implement exactly the same functions as we are able to implement in plain JavaScript, but with type safety.
296+
297+
However, every function taking an element name or an event name as parameter must have type parameters too, making its type signature harder to read.
298+
267299
\subsection{Path-Dependent Types}
268300

301+
This section shows how we can remove the extra type parameters needed in the previous section by using\emph{path-dependent types}. Essentially, the idea is that, instead of using a type parameter, we use a type member. Listings\ref{lst-dt-dom} and\ref{lst-dt-events} show this encoding in Scala. The return type of the\scalacode{createElement} function is\scalacode{name.Element}: it refers to the\scalacode{Element} type member of its\scalacode{name} parameter.
302+
269303
\begin{figure}
270304
\begin{lstlisting}[label=lst-dt-dom]
271305
trait ElementName {
272306
type Element
273307
}
308+
object Div extends ElementName { type Element = DivElement }
309+
object Input extends ElementName { type Element = InputElement }
274310

275-
def createElement(name: ElementName): name.Element = ...
311+
def createElement(name: ElementName): name.Element
276312
\end{lstlisting}
277313
\end{figure}
278314

279315

280316
\begin{figure}
281317
\begin{lstlisting}[label=lst-dt-events]
282318
trait EventName {
283-
typeData
319+
typeEvent
284320
}
285-
object Click extends EventDef { type Data = MouseEvent }
286-
287-
def on(name: EventName)(handler: Rep[name.Data] => Rep[Unit]): Rep[Unit]
321+
object Click extends EventDef { type Event = MouseEvent }
288322

289-
val clicks = on(Click)
290-
clicks(event => println(event.offsetX))
323+
trait EventTarget {
324+
def addEventListener(name: EventName)(handler: name.Event => Unit): Unit
325+
}
291326
\end{lstlisting}
292327
\end{figure}
293328

294-
\section{Validation}
295-
\label{sec-validation}
296-
297-
We show that our encodings support the challenging functions defined in listings\ref{lst-js-comb} and\ref{lst-js-react}.
298-
299-
Listing\ref{lst-generics-comb} and\ref{lst-generics-react} show how these functions can be implemented. They are basically a direct translation from JavaScript to Java.
329+
Implementing listings\ref{lst-js-comb} and\ref{lst-js-react} using this encoding is straightforward, as shown by listings\ref{lst-dt-comb} and\ref{lst-dt-react}, respectively.
300330

301331
\begin{figure}
302-
\begin{lstlisting}[label=lst-generics-comb,language=java]
303-
<A, B> void createAndListenTo(
304-
ElementName<A> tagName,
305-
EventName<B> eventName,
306-
Function2<A, B, Void> listener) {
307-
A element = document.createElement(tagName);
308-
element.addEventListener(eventName, event -> listener.apply(event, element));
332+
\begin{lstlisting}[label=lst-dt-comb]
333+
def createAndListenTo(tagName: ElementName, eventName: EventName, listener: (eventName.Event, tagName.Element) => Unit) = {
334+
val element = document.createElement(tagName)
335+
element.addEventListener(eventName)(event => listener(event, element))
309336
}
310337
\end{lstlisting}
311338
\end{figure}
312339

313340
\begin{figure}
314-
\begin{lstlisting}[label=lst-generics-react,language=java]
315-
<A> Function<Function<A, Void>, Void> observe(EventTarget target, EventName<A> name) {
316-
return listener -> {
317-
target.addEventListener(name, listener);
318-
}
319-
}
341+
\begin{lstlisting}[label=lst-dt-react]
342+
def observe(target: EventTarget, name: EventName) =
343+
(listener: (name.Event => Unit)) => target.addEventListener(name)(listener)
320344
\end{lstlisting}
321345
\end{figure}
322346

347+
With this encoding, the functions using event names or element names are not anymore cluttered with type parameters.
348+
349+
\section{Validation}
350+
\label{sec-validation}
351+
352+
\subsection{Implementation in js-scala}
353+
354+
We implemented our pattern in js-scala~\cite{Kossakowski12_JsDESL}, a Scala library providing JavaScript code generators\footnote{Source code is available at\href{http://github.com/js-scala}{http://github.com/js-scala}}.
355+
323356
\subsection{Limitations}
324357

325358
We do not help with\jscode{getElementById}.
@@ -334,6 +367,8 @@ \section{Related Works}
334367
\section{Conclusion}
335368
\label{sec-conclusion}
336369

370+
We presented two ways to encode dynamically typed browser functions in mainstream statically typed languages like Java and Scala, using\emph{generics} or path-dependent types. Our encoding gives more type safety than existing solutions, while keeping the same expression power and modularity level as the native API.
371+
337372
\bibliographystyle{plain}
338373
\bibliography{references.bib}
339374

‎papers/icwe14/references.bib‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
@comment{x-kbibtex-personnameformatting=<%l><, %f>}
22

3+
@inproceedings{leijen1999domain,
4+
title={Domain specific embedded compilers},
5+
author={Leijen, Daan and Meijer, Erik},
6+
booktitle={ACM Sigplan Notices},
7+
volume={35},
8+
number={1},
9+
pages={109--122},
10+
year={1999},
11+
organization={ACM}
12+
}
13+
314
@incollection{liberty2011reactive,
415
title={Reactive Extensions for JavaScript},
516
author={Liberty, Jesse and Betts, Paul},

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp