From 6dd5088519453bcad5f367b3c6dd3cfeb0e9cd5c Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Wed, 3 Mar 2021 22:17:06 -0500 Subject: Documentation on namespaces --- doc/README.md | 1 + doc/namespace.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/syntax.md | 4 +++- docs/doc/index.html | 1 + docs/doc/namespace.html | 50 +++++++++++++++++++++++++++++++++++++++ docs/doc/syntax.html | 3 ++- 6 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 doc/namespace.md create mode 100644 docs/doc/namespace.html diff --git a/doc/README.md b/doc/README.md index 890cde95..0653e787 100644 --- a/doc/README.md +++ b/doc/README.md @@ -17,6 +17,7 @@ Concepts: - [Functional programming](functional.md) - [Array indices](indices.md) - [The leading axis model](leading.md) +- [Namespaces](namespace.md) - [Function trains](train.md) Primitives: diff --git a/doc/namespace.md b/doc/namespace.md new file mode 100644 index 00000000..818bf485 --- /dev/null +++ b/doc/namespace.md @@ -0,0 +1,63 @@ +*View this file with results and syntax highlighting [here](https://mlochbaum.github.io/BQN/doc/namespace.html).* + +# Namespaces + +A namespace is a type of value that groups together several values (fields) from the same scope. A block or file returns a namespace if it contains any export arrows `⇐` at the top level, and fields from namespaces can be accessed with either dot syntax or destructuring assignment. A namespace that contains `↩` is mutable, so that its fields might change in value. + +The self-hosting BQN used for the online REPL doesn't support namespaces yet, but will eventually. dzaima/BQN does. + +The following quick example shows a few ways to use a namespace returned by `•Import`: + + ns ← •Import "file.bqn" + ⟨something, abbr⇐abbreviation⟩ ← ns # Destructure + ns.DoThing 6 # Dot syntax + +An here's how the contents of file.bqn might look in order to define the variables used above: + + ⟨something, DoThing⟩⇐ # Declare exports + abbreviation ⇐ "sth" # Define and export + _something ← {𝕗} # Separate definition + DoThing ← "TODO"⊸! + +## Uses + +The features of namespaces that make them useful in BQN programming are encapsulation and mutability. But these are exactly the same features that [closures](https://en.wikipedia.org/wiki/Closure_(computer_programming)) provide! In fact a namespace is not much more than a closure with a name lookup system. Consequently namespaces don't really expand the basic functionality of the language, but just make it easier to use. + +Namespaces improve encapsulation by allowing many values to be exported at once. With only one way to call them, functions and modifiers aren't such a good way to define a large part of a program. With a namespace you can define lots of things and expose exactly the ones you want to the rest of the world. For example, it's typical for files to define namespaces. A reader can see the exported values just by searching for `⇐`, and if you're nice, you might declare them all at the beginning of the file. Careful use of exports can guarantee that potentially dangerous functions are used correctly: if it's only valid to call function `B` after function `A` has been called, export `AB⇐{A𝕩⋄B𝕩}` and don't export `B`. + +Mutability means that the behavior of one namespace can change over the course of the program. Mutability is often a liability, so make sure you really need it before leaning too heavily on this property. While there's no way to tell from the outside that a particular namespace is mutable, you can tell it isn't if the source code doesn't contain `↩`, as this is the only way it can modify the variables it contains. + +A namespace that makes use of mutability is essentially an object: a collection of state along with operations that act on it. Object-oriented programming is the other major use of namespaces. Contrary to the name, there's never a need to orient your programming around objects, and it's perfectly fine to use an object here or there when you need to, for instance to build a mutable queue of values. + +## Exports + +The double arrow `⇐` is used to export variables from a block or file, making the result a namespace instead of the result of the last line. There are two ways to export variables. First, `←` in the variable definition can be replaced with `⇐` to export the variable as it's defined. Second, an export statement consisting of an assignment target followed by `⇐`, with nothing to the right, exports the variables in the target and does nothing else. These export statements can be placed anywhere in the relevant program or body, including before declaration or on the last line, and a given variable can be exported any number of times. The block in the example below has two statements that export variables, exporting `a`, `b`, and `c`. + + example ← { + b‿c⇐ # Non-definition exports can go anywhere + a⇐2 # Define and export + b←1+a + c←b‿"str" + } + +## Imports + +There are also two ways to get values out of a namespace, such as `example` defined above. First, it might be used in a destructuring assignment like the one below. This assignment's target looks like a list, where each entry specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name, like `b`, which gives both, or an aliasing expression like `b2⇐b`. In this case, the value `b` from the namespace is used, but it's given the name `b2` instead of `b`. Imported names can be repeated—but the variables defined can't—and all the names can be spelled with any role (the role is ignored). + + ⟨alias⇐a, b, c0‿c1⇐c, b2⇐b⟩ ← example + +If aliasing with `⇐` is never used, the names can be given as a strand with `‿`. + + c‿a ← example + +The arrows `⇐` used for importing don't indicate that the surrounding block is a namespace or export variables. However, a single statement can both import and export, if it's a destructuring assignment and the main assignment arrow is `⇐`. + + ⟨two, vars⟩ ⇐ •Import "stuff.bqn" + +The second way to get a value (just one at a time) from a namespace is dot syntax: write the namespace, then a dot `.`, then another name. + + example.b + + {n⇐7}.n + +The syntax is any subject followed by a dot and then a name. This can be chained like `a.b.c` if a namespace has a value that is also a namespace (and so on). diff --git a/doc/syntax.md b/doc/syntax.md index 88434621..7a0b5eb3 100644 --- a/doc/syntax.md +++ b/doc/syntax.md @@ -84,6 +84,8 @@ Assignment can be used inline in an expression, and its result is always the val ### Exports +See [namespaces](namespace.md): this section is a little out of date. + The double arrow `⇐` is used to export variables from an immediate block or file. It can only be used in these contexts, and not in function or modifier blocks. There are two ways to export variables. First, `←` in the variable definition can be replaced with `⇐` to export the variable as it's defined. Second, an export statement consisting of an assignment target followed by `⇐` with nothing to the right exports the variables in the assignment target and does nothing else. Export statements can be placed anywhere in the relevant program or body, including before declaration or on the last line, and a given variable can be exported any number of times. ⟨alias⇐a, b, c0‿c1⇐c, b2⇐b⟩←{ @@ -93,7 +95,7 @@ The double arrow `⇐` is used to export variables from an immediate block or fi c←b‿"str" } -A block with exports is a *namespace block*, and in versions of BQN without first-class namespaces it can only be used as part of a destructuring assignment. This assignment's target is a list where each element specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name (such as `b` above), which gives both, or a combination of a name, then `:`, then the assignment target. If `:` is never used, the names can be given as a strand with `‿`. To use `:` for aliases, bracket syntax `⟨⟩` is needed. Imported names can be repeated and can be spelled with any role (the role is ignored). +A block with exports is a *namespace block*, and in versions of BQN without first-class namespaces it can only be used as part of a destructuring assignment. This assignment's target is a list where each element specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name (such as `b` above), which gives both, or a combination of the assignment target, then `⇐`, then a name. If `⇐` is never used, the names can be given as a strand with `‿`. To use `⇐` for aliases, bracket syntax `⟨⟩` is needed. Imported names can be repeated and can be spelled with any role (the role is ignored). ## Lists and blocks diff --git a/docs/doc/index.html b/docs/doc/index.html index 4dba1b87..c53b5247 100644 --- a/docs/doc/index.html +++ b/docs/doc/index.html @@ -21,6 +21,7 @@
  • Functional programming
  • Array indices
  • The leading axis model
  • +
  • Namespaces
  • Function trains
  • Primitives:

    diff --git a/docs/doc/namespace.html b/docs/doc/namespace.html new file mode 100644 index 00000000..17ed7cf6 --- /dev/null +++ b/docs/doc/namespace.html @@ -0,0 +1,50 @@ + + + + BQN: Namespaces + + +

    Namespaces

    +

    A namespace is a type of value that groups together several values (fields) from the same scope. A block or file returns a namespace if it contains any export arrows at the top level, and fields from namespaces can be accessed with either dot syntax or destructuring assignment. A namespace that contains is mutable, so that its fields might change in value.

    +

    The self-hosting BQN used for the online REPL doesn't support namespaces yet, but will eventually. dzaima/BQN does.

    +

    The following quick example shows a few ways to use a namespace returned by •Import:

    +
    ns  •Import "file.bqn"
    +something, abbrabbreviation  ns  # Destructure
    +ns.DoThing 6                         # Dot syntax
    +
    +

    An here's how the contents of file.bqn might look in order to define the variables used above:

    +
    something, DoThing     # Declare exports
    +abbreviation  "sth"      # Define and export
    +_something  {𝕗}          # Separate definition
    +DoThing  "TODO"!
    +
    +

    Uses

    +

    The features of namespaces that make them useful in BQN programming are encapsulation and mutability. But these are exactly the same features that closures provide! In fact a namespace is not much more than a closure with a name lookup system. Consequently namespaces don't really expand the basic functionality of the language, but just make it easier to use.

    +

    Namespaces improve encapsulation by allowing many values to be exported at once. With only one way to call them, functions and modifiers aren't such a good way to define a large part of a program. With a namespace you can define lots of things and expose exactly the ones you want to the rest of the world. For example, it's typical for files to define namespaces. A reader can see the exported values just by searching for , and if you're nice, you might declare them all at the beginning of the file. Careful use of exports can guarantee that potentially dangerous functions are used correctly: if it's only valid to call function B after function A has been called, export AB{A𝕩B𝕩} and don't export B.

    +

    Mutability means that the behavior of one namespace can change over the course of the program. Mutability is often a liability, so make sure you really need it before leaning too heavily on this property. While there's no way to tell from the outside that a particular namespace is mutable, you can tell it isn't if the source code doesn't contain , as this is the only way it can modify the variables it contains.

    +

    A namespace that makes use of mutability is essentially an object: a collection of state along with operations that act on it. Object-oriented programming is the other major use of namespaces. Contrary to the name, there's never a need to orient your programming around objects, and it's perfectly fine to use an object here or there when you need to, for instance to build a mutable queue of values.

    +

    Exports

    +

    The double arrow is used to export variables from a block or file, making the result a namespace instead of the result of the last line. There are two ways to export variables. First, in the variable definition can be replaced with to export the variable as it's defined. Second, an export statement consisting of an assignment target followed by , with nothing to the right, exports the variables in the target and does nothing else. These export statements can be placed anywhere in the relevant program or body, including before declaration or on the last line, and a given variable can be exported any number of times. The block in the example below has two statements that export variables, exporting a, b, and c.

    +
    example  {
    +  bc   # Non-definition exports can go anywhere
    +  a2    # Define and export
    +  b1+a
    +  cb"str"
    +}
    +
    +

    Imports

    +

    There are also two ways to get values out of a namespace, such as example defined above. First, it might be used in a destructuring assignment like the one below. This assignment's target looks like a list, where each entry specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name, like b, which gives both, or an aliasing expression like b2b. In this case, the value b from the namespace is used, but it's given the name b2 instead of b. Imported names can be repeated—but the variables defined can't—and all the names can be spelled with any role (the role is ignored).

    +
    aliasa, b, c0c1c, b2b  example
    +
    +

    If aliasing with is never used, the names can be given as a strand with .

    +
    ca  example
    +
    +

    The arrows used for importing don't indicate that the surrounding block is a namespace or export variables. However, a single statement can both import and export, if it's a destructuring assignment and the main assignment arrow is .

    +
    two, vars  •Import "stuff.bqn"
    +
    +

    The second way to get a value (just one at a time) from a namespace is dot syntax: write the namespace, then a dot ., then another name.

    +
    example.b
    +
    +{n7}.n
    +
    +

    The syntax is any subject followed by a dot and then a name. This can be chained like a.b.c if a namespace has a value that is also a namespace (and so on).

    diff --git a/docs/doc/syntax.html b/docs/doc/syntax.html index b77b5660..a2eb77b3 100644 --- a/docs/doc/syntax.html +++ b/docs/doc/syntax.html @@ -150,6 +150,7 @@ ¯3

    Exports

    +

    See namespaces: this section is a little out of date.

    The double arrow is used to export variables from an immediate block or file. It can only be used in these contexts, and not in function or modifier blocks. There are two ways to export variables. First, in the variable definition can be replaced with to export the variable as it's defined. Second, an export statement consisting of an assignment target followed by with nothing to the right exports the variables in the assignment target and does nothing else. Export statements can be placed anywhere in the relevant program or body, including before declaration or on the last line, and a given variable can be exported any number of times.

    aliasa, b, c0c1c, b2b{
       bc   # Non-definition exports can go anywhere
    @@ -158,7 +159,7 @@
       cb"str"
     }
     
    -

    A block with exports is a namespace block, and in versions of BQN without first-class namespaces it can only be used as part of a destructuring assignment. This assignment's target is a list where each element specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name (such as b above), which gives both, or a combination of a name, then :, then the assignment target. If : is never used, the names can be given as a strand with . To use : for aliases, bracket syntax ⟨⟩ is needed. Imported names can be repeated and can be spelled with any role (the role is ignored).

    +

    A block with exports is a namespace block, and in versions of BQN without first-class namespaces it can only be used as part of a destructuring assignment. This assignment's target is a list where each element specifies one of the names exported by the block and what it should be assigned to. The element can be either a single name (such as b above), which gives both, or a combination of the assignment target, then , then a name. If is never used, the names can be given as a strand with . To use for aliases, bracket syntax ⟨⟩ is needed. Imported names can be repeated and can be spelled with any role (the role is ignored).

    Lists and blocks

    Separators

    The characters and , and newline are completely interchangeable and are used to separate expressions. An expression might be an element in a list or a line in a function. Empty sections—those that consist only of whitespace—are ignored. This means that any number of separators can be used between expressions, and that leading and trailing separators are also allowed. The expressions are evaluated in text order: left to right and top to bottom.

    -- cgit v1.2.3