From e858f41dffaee272ffcf4b2cb63a49ad25ebf7d7 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Mon, 15 Mar 2021 15:01:22 -0400 Subject: Highlight namespace dot as a separate token in md.bqn --- docs/doc/oop.html | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'docs/doc/oop.html') diff --git a/docs/doc/oop.html b/docs/doc/oop.html index a683a550..c2c597db 100644 --- a/docs/doc/oop.html +++ b/docs/doc/oop.html @@ -65,7 +65,7 @@

Objects

-

An object in BQN is simply a namespace: its fields and methods are variables in the namespace, and one of these can be accessed outside of the namespace with dot syntax if it's exported with . Unexported variables are instance-private in OOP parlance, meaning that only they're only visible to the object containing them. They could be utilities, or hold state for the object. As an example, the object below implements the Tower of Hanoi puzzle with five disks. You can view the state (a list of disks occupying each of the three rods) with towerOfHanoi.View, or move the top disk from one rod to another with towerOfHanoi.Move.

+

An object in BQN is simply a namespace: its fields and methods are variables in the namespace, and one of these can be accessed outside of the namespace with dot syntax if it's exported with . Unexported variables are instance-private in OOP parlance, meaning that only they're only visible to the object containing them. They could be utilities, or hold state for the object. As an example, the object below implements the Tower of Hanoi puzzle with five disks. You can view the state (a list of disks occupying each of the three rods) with towerOfHanoi.View, or move the top disk from one rod to another with towerOfHanoi.Move.

towerOfHanoi  {
   l  ¨500
   View  {𝕤
@@ -85,15 +85,15 @@
 

Two fields l and Transfer aren't exported, for two different reasons. l encodes the state of the tower, but it's often better to expose it with the function View instead to allow the internal representation to be changed freely. Transfer is just a utility function. While it's not dangerous to use outside of the object, there's no reason to expose it through towerOfHanoi's interface. If it's wanted in another place it should be moved to a common location.

Here are the results of a few applications of these functions.

    t  towerOfHanoi
-    t.View@
+    t.View@
   0 1 2 3 4  ⟨⟩ ⟨⟩ 
-    t.Move 02
+    t.Move 02
   1 2 3 4  ⟨⟩  0  
-    t.Move 12
+    t.Move 12
 ! "No disk to move"
-    t.Move 01
+    t.Move 01
   2 3 4   1   0  
-    t.Move 21
+    t.Move 21
   2 3 4   0 1  ⟨⟩ 
 

Classes

@@ -119,18 +119,18 @@
MakeQueue  {𝕤
   the{SetN{h𝕩}}
   Node{v𝕩ne  SetN{n𝕩}}
-  Push{t.SetN nNode 𝕩  tn}
+  Push{t.SetN nNode 𝕩  tn}
   Pop {𝕤vh.v{t𝕩}(e=)hh.nv}
 }
 
-

Unlike a stack, a node's successor isn't known when it's created, and it has to be set. You might be inclined to make n settable directly, but we'll get more mileage out of a setter function SetN. This allows us to create a pseudo-node e (for "empty") indicating there are no values in the queue. Because it has no .v field, if h is e then Pop gives an error (but in a real implementation you'd want to test explicitly instead in order to give an appropriate error message). In fact it doesn't have an n field, and essentially uses the queue head h instead. With this empty "node", the queue definition is straightforward. The only tricky part to remember is that if Pop removes the last node, resulting in e=h, then the tail has to be set to e as well, or it will keep pointing to the removed node and cause bugs.

+

Unlike a stack, a node's successor isn't known when it's created, and it has to be set. You might be inclined to make n settable directly, but we'll get more mileage out of a setter function SetN. This allows us to create a pseudo-node e (for "empty") indicating there are no values in the queue. Because it has no .v field, if h is e then Pop gives an error (but in a real implementation you'd want to test explicitly instead in order to give an appropriate error message). In fact it doesn't have an n field, and essentially uses the queue head h instead. With this empty "node", the queue definition is straightforward. The only tricky part to remember is that if Pop removes the last node, resulting in e=h, then the tail has to be set to e as well, or it will keep pointing to the removed node and cause bugs.

Composition

BQN classes don't support inheritance because there's no way to extend an existing class with new fields. But a lot of OOP enthusiasts these days are promoting composition over inheritance, and here BQN does pretty well. Forwarding methods from another class is as simple as a multiple assignment, like View below (in a real program undoableTowerOfHanoi should almost certainly be a class, but I introduced towerOfHanoi before classes, and I'm not about to write it again just to add an 𝕤).

undoableTowerOfHanoi  {
   PushPop  MakeStack@     # Copy methods as private
   View  ttowerOfHanoi   # Copy and export
-  Move  t.Move  Push
-  Undo  t.MovePop
+  Move  t.Move  Push
+  Undo  t.MovePop
 }
 

This class composes a Tower of Hanoi with an undo stack that stores previous moves. To undo a move from a to b, it moves from b to a, although if you felt really fancy you might define Move in towerOfHanoi instead with 𝕊𝕩: 𝕊⌽𝕩.

-- cgit v1.2.3