diff options
Diffstat (limited to 'docs/book/MODULES.html')
-rw-r--r-- | docs/book/MODULES.html | 66 |
1 files changed, 39 insertions, 27 deletions
diff --git a/docs/book/MODULES.html b/docs/book/MODULES.html index 4ee1fe5..738ee93 100644 --- a/docs/book/MODULES.html +++ b/docs/book/MODULES.html @@ -7,7 +7,7 @@ <!-- Custom HTML head --> - + <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="theme-color" content="#ffffff"> @@ -178,18 +178,46 @@ <p>! This section is <strong>incomplete</strong>. Proceed with caution.</p> </blockquote> <p>Puck has a first-class module system, inspired by such expressive designs in the ML family.</p> -<h2 id="using-modules"><a class="header" href="#using-modules">Using Modules</a></h2> -<pre><code class="language-puck"></code></pre> -<p>Modules package up code for use by others. Identifiers known at compile time may be part of a <em>module signature</em>: these being constants, functions, macros, types, and other modules themselves. They may be made accessible to external users by prefixing them with the <code>pub</code> keyword. Files are modules, named with their filename. The <code>mod</code> keyword followed by an identifier and an indented block of code explicitly defines a module, inside of the current module. Modules are first class: they may be bound to constants (having the type <code>: mod</code>) and publicly exported, or bound to local variables and passed into functions for who knows what purpose.</p> -<p>The <code>use</code> keyword lets you use other modules. The <code>use</code> keyword imports public symbols from the specified module into the current scope <em>unqualified</em>. This runs contrary to expectations coming from most other languages: from Python to Standard ML, the standard notion of an "import" usually puts the imported symbols behind another symbol to avoid "polluting the namespace". As Puck is strongly typed and allows overloading, however, the author sees no reason for namespace pollution to be of concern. These unqualified imports have the added benefit of making uniform function call syntax more widely accessible. It is inevitable that identifier conflicts will exist on occasion, of course: when this happens, the compiler will force qualification (this then does restrict uniform function call syntax).</p> -<pre><code class="language-puck"></code></pre> +<h2 id="what-are-modules"><a class="header" href="#what-are-modules">What are Modules?</a></h2> +<pre><code class="language-puck">pub mod stack = + pub type Stack[T] = class + init(static type Self): Stack[T] + push(mut Self, val: T) + pop(mut Self): T? + peek(lent Self): lent T? + + pub mod list = + type ListStack[T] = list[T] + + pub func init[T](self: static type ListStack[T]): Stack[T] = [] + pub func push[T](self: mut ListStack[T], val: T) = self.push(T) + pub func pop[T](self: mut ListStack[T]): T? = self.pop + pub func peek[T](self: lent ListStack[T]): lent T? = + if self.len == 0 then None else Some(self.last) + +use stack.list + +let a = ListStack[int].init +print a.len # error: unable to access method on private type outside its module + +a.push(5) +print a.pop # Some(5) +</code></pre> +<p>Modules package up code for use by others. Identifiers known at compile time may be part of a module: these being constants, functions, macros, types, and other modules themselves. Such identifiers may be made accessible outside of the module by prefixing them with the <code>pub</code> keyword.</p> +<p>Importantly, <em>files</em> are implicitly modules, public and named with their filename. The <code>mod</code> keyword followed by an identifier and an indented block of code explicitly defines a module, inside of the current module. Modules are first class: they may be bound to constants (having the type <code>: mod</code>) and publicly exported, or bound to local variables and passed into functions for who knows what purpose.</p> +<h2 id="using-modules"><a class="header" href="#using-modules">Using modules</a></h2> +<p>The <code>use</code> keyword lets you use other modules.</p> +<p>The <code>use</code> keyword imports public symbols from the specified module into the current scope <em>unqualified</em>. This runs contrary to expectations coming from most other languages: from Python to Standard ML, the standard notion of an "import" puts the imported symbols behind another symbol to avoid "polluting the namespace". As Puck is strongly typed and allows overloading, however, we see no reason for namespace pollution to be of concern. These unqualified imports have the added benefit of making <em>uniform function call syntax</em> more widely accessible. It is inevitable that identifier conflicts will exist on occasion, of course: when this happens, the compiler will force qualification (this then does restrict uniform function call syntax). We discuss this more later.</p> <p>Nonetheless, if qualification of imports is so desired, an alternative approach is available - binding a module to a constant. Both the standard library and external libraries are available behind identifiers without use of <code>use</code>: <code>std</code> and <code>lib</code>, respectively. (FFI and local modules will likely use more identifiers, but this is not hammered out yet.) A submodule - for example, <code>std.net</code> - may be bound in a constant as <code>const net = std.net</code>, providing all of the modules' public identifiers for use, as fields of the constant <code>net</code>. We will see this construction to be extraordinarily helpful in crafting high-level public APIs for libraries later on.</p> -<p>Multiple modules can be imported at once, i.e. <code>use std.[logs, tests]</code>, <code>use lib.crypto, lib.http</code>. The standard namespaces (<code>std</code>, <code>lib</code>) deserve more than a passing mention. There are several of these: <code>std</code> for the standard library, <code>lib</code> for all external libraries, <code>crate</code> for the top-level namespace of a project (subject to change), <code>this</code> for the current containing module (subject to change)... In addition: there are a suite of <em>language</em> namespaces, for FFI - <code>rust</code>, <code>nim</code>, and <code>swift</code> preliminarily - that give access to libraries from other languages. Recall that imports are unqualified - so <code>use std</code> will allow use of the standard library without the <code>std</code> qualifier (not recommended: several modules have common names), and <code>use lib</code> will dump every library it can find into the global namespace (even less recommended). </p> +<pre><code class="language-puck">use std.[logs, test] +use lib.crypto, lib.http +</code></pre> +<p>Multiple modules can be imported at once. The standard namespaces deserve more than a passing mention. There are several of these: <code>std</code> for the standard library, <code>lib</code> for all external libraries, <code>pkg</code> for the top-level namespace of a project, <code>this</code> for the current containing module... In addition: there are a suite of <em>language</em> namespaces, for FFI - <code>rust</code>, <code>nim</code>, and <code>swift</code> preliminarily - that give access to libraries from other languages. Recall that imports are unqualified - so <code>use std</code> will allow use of the standard library without the <code>std</code> qualifier (not recommended: several modules have common names), and <code>use lib</code> will dump the name of every library it can find into the global namespace (even less recommended).</p> <h2 id="implicit-modules"><a class="header" href="#implicit-modules">Implicit Modules</a></h2> -<p>A major goal of Puck's module system is to allow the same level of expressiveness as the ML family, while cutting down on the extraneous syntax and boilerplate needed to do so. As such, access modifiers are written directly inline with their declaration, and the file system structure is reused to form an implicit module system for internal use. This - particularly the former - <em>limits</em> the structure a module can expose at first glance, but we will see later that interfaces recoup much of this lost specificity.</p> -<p>We mentioned that the filesystem forms an implicit module structure. This begets a couple of design choices. Module names <strong>must</strong> be lowercase, for compatibility with case-insensitive filesystems. Both a file and a folder with the same name can exist. Files within the aforementioned folder are treated as submodules of the aforementioned file. This again restricts the sorts of module structures we can build, but we will again see later that this restriction can be bypassed.</p> -<p>The <code>this</code> and <code>crate</code> modules are useful for this implicit structure...</p> -<h2 id="defining-interfaces"><a class="header" href="#defining-interfaces">Defining Interfaces</a></h2> +<p>A major goal of Puck's module system is to allow the same level of expressiveness as the ML family, while cutting down on the extraneous syntax and boilerplate needed to do so. As such, access modifiers are written directly inline with their declaration, and the file system structure is reused to form an implicit module system for internal use. This - particularly the former - <em>limits</em> the structure a module can expose at first glance, but we will see later that classes recoup much of this lost specificity.</p> +<p>We mentioned that the filesystem forms an implicit module structure. This begets a couple of design choices. Module names <strong>must</strong> be lowercase, for compatibility with case-insensitive filesystems. Both a file and a folder with the same name can exist. Files within the aforementioned folder are treated as submodules of the aforementioned file. This again restricts the sorts of module structures we can build, but we will see later that this restriction can be bypassed.</p> +<p>The <code>this</code> and <code>pkg</code> modules are useful for this implicit structure...</p> +<h2 id="defining-interfaces"><a class="header" href="#defining-interfaces">Defining interfaces</a></h2> <p>...</p> <h2 id="defining-an-external-api"><a class="header" href="#defining-an-external-api">Defining an External API</a></h2> <p>The filesystem provides an implicit module structure, but it may not be the one you want to expose to users.</p> @@ -224,22 +252,6 @@ </div> - <!-- Livereload script (if served using the cli tool) --> - <script> - const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; - const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload"; - const socket = new WebSocket(wsAddress); - socket.onmessage = function (event) { - if (event.data === "reload") { - socket.close(); - location.reload(); - } - }; - - window.onbeforeunload = function() { - socket.close(); - } - </script> |