Vocabulary/ObjectOrientedProgramming

From J Wiki
Jump to navigation Jump to search

Back to: Vocabulary

Object-Oriented Programming

This is the executive summary of J's facilities for object-oriented programming. For full details, look at the discussion of locales.

Definitions: class and instance

A class is a namespace that is populated with nouns and verbs. In J, classes are named locales. Usually a class exists only to create instances that use the names defined in the class.

An instance is a namespace that has access to the names in a class. It is said to be an instance of that class. In J, instances are numbered locales.

Referring to an instance

Names inside an instance, which is a numbered locale, are accessed through a noun that holds the number of the locale. This number is assigned when the instance is created. It can be assigned like any other noun.

If the noun holding the instance is instname, you would refer to the name abc in the instance using the syntax:

   abc__instname

You can refer any name defined in the instance this way, noun or verb.

Defining a class

You define a class by setting the implied locale to the name of the class, and then assigning the names that define the class. You should always define the special names create and destroy, which create/destroy instances of the class.

Define a class like this:

cocurrent 'classname'
NB. define any names shared by all instances here (*** A ***)
create =: 3 : 0
NB. y holds the arguments used to create an instance.
NB. assignments made inside a verb are private to the instance (*** B ***)
)

destroy =: 3 : 0
NB. release any resources acquired
codestroy''   NB. release the instance, when it finishes execution
)

Names shared by all instances

Names that are to be visible to all instances should be assigned outside any verb, as shown at A above. These names are assigned in the locale of the class, not the instance, and are inherited by each instance of the class.

Names local to a single instance

Names assigned inside an instance (as B above) are visible only inside the instance and are not seen by other instances of the same class.

Inheritance of names

Names that are defined in the class, but not in the instance, are visible in the instance. This is an example of J's path mechanism.

Note that if an instance assigns a name, the name will be assigned in the instance, not the class. Thus, if the create verb wants to keep a list of all the instances that have been created, it needs:

cocurrent 'newclass'
allinstances =: 0$a:  NB. List  of all instances
create =: 3 : 0
allinstances_newclass_ =: allinstances , coname''
)

By assigning to allinstances_newclass_, the name in the class was updated. If the assignment had been made to allinstances, an assignment would be made inside the instance, which would not be useful.

Public names

Notwithstanding the description above of names as being visible either within a class or within a single instance, you should know that all names defined in a class or instance are public, in that any J sentence can get to them if it knows the instance or class name. You are pledged not to use this ability to produce spaghetti code.

Creating an instance of a class

To create an instance of class myclass, write

   refname =: 0&".@> parameters conew 'myclass'

conew calls

  create_myclass_ parameters

which creates an instance. The result, which is the number of the instance, is assigned to refname and you can use it later in sentences like

  setoptions__refname optionlist

refname is an integer atom. A numbered instance can be referred to by a locative that is one of

  • the number
  • the number boxed
  • the string form of the number, boxed

Using the integer-atom form is most efficient.

Creating a class that extends another class (class inheritance)

To create a class iclass that inherits from a base class bclass, write:

   cocurrent 'iclass'
   coinsert 'bclass'   NB. This makes iclass inherit from bclass
...
create =: 3 : 0
create_bclass_ f. arguments  NB. Pass on to bclass what it needs to initialize
NB. Initialization of the iclass info here
)
destroy =: 3 : 0
NB. Release resources acquired for this instance
destroy_bclass_ f. ''   NB. Release resources acquired by inherited class, including this instance
)

That's all you have to do. That f. in create and destroy is vital.

Rules for names

In typical use (as was described here), an object will have a namespace and its class will have a namespace. Verbs inside the object namespace would by default reference the object namespace and would inherit references to definitions of names provided in the class namespace which have not been overridden in the object namespace, much like the class itself would inherit definitions from parent classes.

Adverbs and conjunctions may be defined in a class, but they will execute in the calling namespace rather than in the object or class namespace.

So, names used in classes (and objects) should usually be verbs or nouns.

(The exception, of course, is when access to the calling namespace is needed. Here, it's also important to explicitly reference the class or object, as needed.)

Here's a minimal example using a class which has not been instantiated as an object:

   cocurrent'base'
   test_test_=: {{ echo m,y,;coname'' }}
   test2_test_=: '...'test_test_
   '...' test_test_'|'
...|base
   test2_test_ '|'
...|test

Destroying an instance

When an instance has done its work, you have to destroy it. There is no automatic garbage collection. Simply write

   destroy__refname ''