diff --git a/deps.tex b/deps.tex index 3ced583..2a99206 100644 --- a/deps.tex +++ b/deps.tex @@ -1,12 +1,12 @@ \begin{frame}[fragile] - \frametitle{Deep Dive into Dependency Calculation} + \frametitle{Deep dive into dependency calculation} \begin{columns} - \begin{column}{0.55\textwidth} - \begin{verbatim} + \begin{column}{0.5\textwidth} + \begin{Verbatim}[fontsize=\small] component HelloWorld { model { - name: String = "hello", + name: String = "", } view { @@ -14,7 +14,7 @@ component HelloWorld { "Hello, " {name} "!" } } - \end{verbatim} + \end{Verbatim} \end{column} \begin{column}{0.3\textwidth} Points of interest: @@ -28,36 +28,45 @@ component HelloWorld { \end{frame} \begin{frame} - \frametitle{Generated Dependency Chart} + \frametitle{Generated dependency chart} \begin{center} - \includegraphics[width=0.6\textwidth]{{helloworld.dot}.png} + \includegraphics[width=0.6\textwidth]{{./dot/helloworld.dot}.pdf} \end{center} \end{frame} \begin{frame} - \frametitle{Generated Dependency Chart} + \frametitle{Generated dependency chart} \begin{columns} \begin{column}{0.4\textwidth} - \includegraphics[width=\textwidth]{{helloworld.dot}.png} + \includegraphics[width=\textwidth]{{./dot/helloworld.dot}.pdf} \end{column} \begin{column}{0.5\textwidth} - \begin{itemize} - \item All possible dependent actors are uniquely identified. + \begin{itemize}[<+>] \item Symbolizes all interactions within the application. + \item All possible dependent actors are uniquely identified. \item Simple DFS will tell us all updates that need to occur. \end{itemize} \end{column} \end{columns} \end{frame} -\begin{frame}[fragile] - \frametitle{Case Study 2: Dependencies of TodoMVC} +\begin{frame} + \frametitle{Case study 2: TodoMVC} - \includegraphics[width=\textwidth]{{todomvc.dot}.png} \begin{center} - \begin{Verbatim}[fontsize=\tiny] + \includegraphics[width=0.7\textwidth]{./todomvc.png} + \end{center} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Case study 2: dependencies of TodoMVC} + + \begin{center} + \includegraphics[width=0.85\textwidth]{{./dot/todomvc.dot}.pdf} + + \begin{BVerbatim}[fontsize=\tiny] component TodoMVC { model { value: String = "", @@ -65,8 +74,9 @@ component TodoMVC { } view { - + } } - \end{Verbatim} + \end{BVerbatim} \end{center} +\end{frame} + +\begin{frame} + \frametitle{Challenges with TodoMVC} + + \begin{itemize} + \item Everything within iterator must be parameterized. + \begin{itemize} + \item Generated code must be parameterized as well. + \end{itemize} + \item "Reconciliation", or re-updating the model on change. + \begin{itemize} + \item Consider hash-map-backed linked list implementations. + \end{itemize} + \end{itemize} \end{frame} \ No newline at end of file diff --git a/dot/component_backend.dot b/dot/component_backend.dot new file mode 100644 index 0000000..1cce7b2 --- /dev/null +++ b/dot/component_backend.dot @@ -0,0 +1,32 @@ +digraph { + subgraph { + backend [label = "trait Backend"] + web [label = "struct Web;"] + native [label = "struct Native;"] + + web_back_impl [label = "impl Backend for Web", shape="rectangle"] + native_back_impl [label = "impl Backend for Native", shape="rectangle"] + + web -> web_back_impl + web_back_impl -> backend + + native -> native_back_impl + native_back_impl -> backend + + ib_trait [label = "trait InputBoxTrait { type Backend; }"] + ib_web [label = "struct InputBoxWeb {\l web_ref: Reference,\l}\l"] + ib_native [label = "struct InputBoxNative {\l gl_ctx: GlContext,\l}\l"] + + ib_web_trait_impl [label = "impl InputBoxTrait for InputBoxWeb {\l type Backend = Web;\l}\l", shape="rectangle"] + ib_native_trait_impl [label = "impl InputBoxTrait for InputBoxNative {\l type Backend = Native;\l}\l", shape="rectangle"] + + ib_web_trait_impl -> ib_trait + ib_native_trait_impl -> ib_trait + + ib_web -> ib_web_trait_impl + ib_web_trait_impl -> web + + ib_native -> ib_native_trait_impl + ib_native_trait_impl -> native + } +} \ No newline at end of file diff --git a/dot/component_backend.dot.pdf b/dot/component_backend.dot.pdf new file mode 100644 index 0000000..8f37676 Binary files /dev/null and b/dot/component_backend.dot.pdf differ diff --git a/dot/helloworld.dot b/dot/helloworld.dot index 976f861..19257ee 100644 --- a/dot/helloworld.dot +++ b/dot/helloworld.dot @@ -3,5 +3,6 @@ digraph { 1 [label="ModelValue(\"name\")"] 2 [label="RsxSpan(\"sym_2\")"] 0 -> 1 + 1 -> 0 1 -> 2 } diff --git a/dot/helloworld.dot.pdf b/dot/helloworld.dot.pdf new file mode 100644 index 0000000..b9287fe Binary files /dev/null and b/dot/helloworld.dot.pdf differ diff --git a/dot/todomvc.dot b/dot/todomvc.dot index 54f5f8d..5e57182 100644 --- a/dot/todomvc.dot +++ b/dot/todomvc.dot @@ -1,13 +1,20 @@ digraph { rankdir = "LR"; - 0 [label="RsxAttr(\"sym_0\", \"value\")"] + subgraph { + rank = "source"; + 0 [label="RsxAttr(\"sym_0\", \"value\")"] + 2 [label="CodeSeg(\"sym_3\")"] + } 1 [label="ModelValue(Leaf(\"value\"))"] - 2 [label="CodeSeg(\"sym_3\")"] 3 [label="ModelValue(Leaf(\"todos\"))"] 4 [label="RsxEvent(\"sym_0\", \"submit\")"] - 5 [label="CodeSeg(\"sym_9\")"] - 6 [label="Iterator(\"sym_8\")"] + subgraph { + rank = "same"; + 5 [label="CodeSeg(\"sym_9\")"] + 6 [label="Iterator(\"sym_8\")"] + 7 [label="RsxSpan(\"sym_10\")"] + } 0 -> 1 1 -> 0 2 -> 3 @@ -15,4 +22,5 @@ digraph { 4 -> 2 5 -> 6 3 -> 5 + 6 -> 7 } diff --git a/dot/todomvc.dot.pdf b/dot/todomvc.dot.pdf new file mode 100644 index 0000000..a7bef76 Binary files /dev/null and b/dot/todomvc.dot.pdf differ diff --git a/general.tex b/general.tex new file mode 100644 index 0000000..fb40484 --- /dev/null +++ b/general.tex @@ -0,0 +1,167 @@ +\begin{frame} + \frametitle{Interlude: Generalization} + + \begin{itemize} + \item All generated code must never refer to specific implementations. + \item Whether or not a specific component is implemented should be determined at compile time. + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Traits} + + \begin{itemize} + \item Traits are interfaces; describe a set of methods. + \item Traits are constraints; they limit function input. + \item Traits are markers; they can indicate certain properties. + \end{itemize} + + \begin{center} + \begin{BVerbatim}[fontsize=\small] +trait Iterator { + type Item; + fn next(&mut self) -> Option; +} +fn for_each(mut iter: I, func: F) + where I: Iterator, F: Fn(T) { + loop { + match iter.next() { + Some(next) => func(next), + None => return, + } + } +} + \end{BVerbatim} + \end{center} +\end{frame} + +\begin{frame}[fragile] + \frametitle{How can we use traits to our advantage?} + + \begin{itemize} + \item Have a \texttt{Backend} trait to represent different backends + \end{itemize} + + \begin{center} + \begin{BVerbatim} +trait Backend { + fn func1(...) -> (...); +} + \end{BVerbatim} + \end{center} +\end{frame} + +\begin{frame}[fragile] + \frametitle{How can we use traits to our advantage?} + + \begin{itemize} + \item Have a \texttt{Component} trait to represent different components + \item \texttt{Component}s are \textit{parameterized} by backends + \end{itemize} + + \begin{center} + \begin{BVerbatim} +trait Component { + fn foo(...) -> Bar; +} + \end{BVerbatim} + \end{center} +\end{frame} + +\begin{frame}[fragile] + \frametitle{How can we use traits to our advantage?} + + \begin{itemize} + \item Individual components implement a trait on a specific backend. + \item If there's no implementation, the compile will fail. + \end{itemize} + + \begin{center} + \begin{BVerbatim} +struct InputBox { + some_field_1: SomeType1, + some_field_2: SomeType2, +} + +// Now we can use InputBox for web targets! +impl Component for InputBox { + fn foo(...) -> Bar { + (...) + } +} + \end{BVerbatim} + \end{center} +\end{frame} + +\begin{frame}[fragile] + \frametitle{It's not that easy...} + + \begin{itemize} + \item \textbf{Problem:} all backends now share the same data structure. + \item A web input box needs different data than a native one. + \end{itemize} + + \begin{columns} + \begin{column}{0.4\textwidth} + \begin{Verbatim} +struct InputBoxWeb { + web_ref: Reference, +} + \end{Verbatim} + \end{column} + \begin{column}{0.4\textwidth} + \begin{Verbatim} +struct InputBoxNative { + gl_ctx: GlContext, +} + \end{Verbatim} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Don't limit components or backends} + + We don't want to end up in a scenario where we're enumerating all backends or components. For example: + + \vspace{1em} + \begin{columns} + \begin{column}{0.4\textwidth} + \begin{Verbatim} +enum InputBox { + Web(...), + Native(...), + ... +} + \end{Verbatim} + + \vspace{0.5em} + \small{What happens when we add a new backend?} + \end{column} + \begin{column}{0.4\textwidth} + \begin{Verbatim} +trait Backend { + type InputBox; + type Button; + ... +} + \end{Verbatim} + + \vspace{0.5em} + \small{What happens when we add a new component?} + \end{column} + \end{columns} +\end{frame} + +\begin{frame} + \frametitle{Potential model} + + \begin{center} + \includegraphics[width=.85\textwidth]{{./dot/component_backend.dot}.pdf} + \end{center} + + \begin{itemize} + \item \small{How do we discover the concrete implementation from the abstract trait?} + \end{itemize} +\end{frame} + diff --git a/main.tex b/main.tex index d67dd24..dcb4e4f 100644 --- a/main.tex +++ b/main.tex @@ -6,14 +6,12 @@ \usepackage{graphicx} \usepackage{fancyvrb} -\graphicspath{ {./dot/} } - \setbeamercovered{transparent} \title{enterprise} \subtitle{UI Framework Project} \author{Michael Zhang} -\date[\today]{SIFT Interview, \today} +\date{\today} \begin{document} @@ -23,7 +21,18 @@ \end{frame} \begin{frame} - \frametitle{High-Level Goals} + \frametitle{What's out there today?} + + \begin{itemize}[<+>] + \item React: Immediate-mode style framework + \item Elm: Functional message-passing framework + \item Svelte: Compile-time framework + \item Roll your own... ? + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{High-level goals} \begin{itemize}[<+>] \item Declarative-style programming. @@ -32,9 +41,6 @@ \item No framework bloat. \note{enterprise is more like a compiler than a framework in the sense that the code it generates doesn't need to contain the actual compilation process.} - \item Ahead-of-time guarantees. - \note{Another benefit of it being a compiler is that it is difficult to get run-time errors. If it compiles, it works.} - \item Separation of business logic and implementation. \note{Talk about Epic?} \end{itemize} @@ -53,7 +59,7 @@ \begin{verbatim} component HelloWorld { model { - name: String = "hello", + name: String = "", } view { @@ -78,10 +84,12 @@ \include{deps} +\include{general} + \include{codegen} \begin{frame} - \frametitle{Future Work} + \frametitle{Future work} \begin{itemize} \item Full DSL, independent from Rust. @@ -89,6 +97,8 @@ \item Asynchronous event handlers. \item Eliminating unnecessary model stores. \item Connecting to other frameworks (GTK, Iced, etc.) + \item Interpreted executor for fast prototyping. + \item Backend code generation. \end{itemize} \end{frame} diff --git a/parsing.tex b/parsing.tex index e0a1464..cc72d07 100644 --- a/parsing.tex +++ b/parsing.tex @@ -1,18 +1,18 @@ \begin{frame}[fragile] - \frametitle{Deep Dive into Parsing DSL Syntax} + \frametitle{Deep dive into parsing DSL syntax} \begin{columns} \begin{column}{0.3\textwidth} - \begin{itemize} + \begin{itemize}[<+>] \item Hand-rolled recursive-descent parser. \item Why not use LR parser generator? \end{itemize} \end{column} - \begin{column}{0.55\textwidth} - \begin{verbatim} + \begin{column}{0.5\textwidth} + \begin{Verbatim}[fontsize=\small] component HelloWorld { model { - name: String = "hello", + name: String = "", } view { @@ -20,7 +20,7 @@ component HelloWorld { "Hello, " {name} "!" } } - \end{verbatim} + \end{Verbatim} \end{column} \end{columns} \end{frame} @@ -30,15 +30,15 @@ component HelloWorld { \begin{columns} \begin{column}{0.4\textwidth} - \begin{verbatim} + \begin{Verbatim} // proc-macro library -pub enum TokenTree { +enum TokenTree { Group(Group), Ident(Ident), Punct(Punct), Literal(Literal), } - \end{verbatim} + \end{Verbatim} \end{column} \begin{column}{0.4\textwidth} \begin{itemize} @@ -51,3 +51,58 @@ pub enum TokenTree { \end{columns} \end{frame} +\begin{frame}[fragile] + \frametitle{Abstract syntax} + + \begin{center} + \begin{BVerbatim}[fontsize=\small] +struct Component { + name: String, + model: ModelMap, + view: Vec, +} + +enum Rsx { + Elem(Elem), + Code(Context, Expr), + Text(String), + ForLoop(Pat, Expr, Type, Vec), +} + +... + \end{BVerbatim} + \end{center} +\end{frame} + +\begin{frame} + \frametitle{Checking your work.. with property testing} + + \begin{itemize}[<+>] + \item Define certain properties about the procedures. + \item Define types of data that can be passed in. + \item Create "strategies" for randomly generating complex data. + \item Computer generates input cases based on the strategies. + \item Bonus: input cases are "shrunk" down to the minimal case. + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Property testing example} + + \begin{Verbatim}[fontsize=\small] +proptest! { + #[test] + fn tokens_parse_compatibility(tree in arbitrary_component()) { + // turn the input tree into tokens and back + let tokens = tree.to_token_stream(); + let mut visitor = Visitor::from_tokens(tokens.clone()); + let tree2 = visitor.next().unwrap().unwrap(); + + // compare the trees + prop_assert_eq!(tree.name, tree2.name); + prop_assert_eq!(tree.model, tree2.model); + prop_assert_eq!(tree.view, tree2.view); + } +} + \end{Verbatim} +\end{frame} \ No newline at end of file diff --git a/todomvc.png b/todomvc.png new file mode 100644 index 0000000..bcba4d0 Binary files /dev/null and b/todomvc.png differ diff --git a/watch.sh b/watch.sh index 3792e4b..78e89b5 100755 --- a/watch.sh +++ b/watch.sh @@ -8,6 +8,6 @@ killgroup() { kill 0 } -watchexec -w dot -e dot "dot -Tpng -O dot/*.dot" & +watchexec -w dot -e dot "dot -Tpdf -O dot/*.dot" & watchexec -e tex "tectonic main.tex" & wait \ No newline at end of file