## `slot` -- method or entry of a domain or a function environment

#### Introduction

`slot(`d, "n"`)` returns the value of the slot named `"n"` of the object `d`.

`slot(`d, "n", v`)` creates or changes the slot `"n"`. The value `v` is assigned to the slot.

#### Call(s)

d :: n `slot(d, "n")`
d :: n := v `slot(d, "n", v)`
object :: dom `slot(object, "dom")`

#### Parameters

`d` | - | a domain or a function environment
`n` | - | the name of the slot: an identifier
`v` | - | the new value of the slot: an arbitrary MuPAD object
`object` | - | an arbitrary MuPAD object

#### Returns

`slot(`d, "n"`)` returns the value of the slot; `slot(`d, "n", v`)` returns the object `d` with the added or changed slot; `slot(`object, "dom"`)` returns the domain type of the object.

### Overloadable:

`d`

#### Further Documentation

Section 5.7 of the document "From MuPAD 1.4 to MuPAD 2.0".

#### Related Functions

`DOM_DOMAIN`, `DOM_FUNC_ENV`, `domain`, `funcenv`, `newDomain`

#### Details

- The function `slot` is used for defining methods and entries of data types (domains) or for defining attributes of function environments. Such methods, entries, or attributes are called slots. They allow to overload system functions by user defined domains and function environments. See the ``Background'' section below for further information.
- Any MuPAD object has a special slot named `"dom"`. It holds the domain the object belongs to: `slot(`object, "dom"`)` is equivalent to `domtype(object)`. The value of this special slot cannot be changed. Cf. example 1.
- Apart from the special slot `"dom"`, only domains and function environments may have further slots.

  The call `slot(`d, "n"`)` is equivalent to `d::n`. It returns the value of the slot.

  The call `slot(`d, "n", v`)` returns the object `d` with an added or changed slot `"n"` bearing the value `v`.

- For a function environment `d`, the call `slot(`d, "n", v`)` returns a copy of `d` with the changed slot `"n"`. The function environment `d` itself is not changed! Use the assignment `d := slot(d, "n", v)` to modify `d`. Cf. example 2.

  For a domain `d`, however, the call `slot(`d, "n", v`)` modifies `d` as a side-effect! This is the so-called ``reference effect'' of domains. Cf. example 3.

- If a non-existing slot is accessed, `FAIL` is returned as the value of the slot. Cf. example 4.
- The `::`-operator is a shorthand notation to access a slot.

  The expression `d::n`, when not appearing on the left hand side of an assignment, is equivalent to `slot``(d, "n")`.

  The command `d::n := v` assigns the value `v` to the slot `"n"` of `d`. This assignment is almost equivalent to changing or creating a slot via `d:= slot(d, "n", v)`. Note the following subtle semantical difference between these assignments: in `d::n := v`, the identifier `d` is evaluated with level 1, i.e., the slot `"n"` is attached to the value of `d`. In `slot(d, "n", v)`, the identifier `d` is fully evaluated. See example 6.

- With `delete d::n` or `delete slot(d,"n")`, the slot `"n"` of the function environment or the domain `d` is deleted. Cf. example 5. The special slot `"dom"` cannot be deleted.
- The first argument of `slot` is not flattened. This allows to access the slots of expression sequences and `null()` objects. Cf. example 7.
- For domains, there is a special mechanism to create new values for slots on demand. If a non existing slot is read, the method `"make_slot"` of the domain is called in order to create the slot. If such a method does not exist, `FAIL` is returned. Cf. example 8.
- `slot` is a function of the system kernel.

#### Example 1

Every object has the slot `"dom"`:

    >> slot(x, "dom") = domtype(x),
       slot(45, "dom") = domtype(45),
       slot(sin, "dom") = domtype(sin)

          DOM_IDENT = DOM_IDENT, DOM_INT = DOM_INT,

             DOM_FUNC_ENV = DOM_FUNC_ENV

#### Example 2

Here we access the existing `"float"` slot of the function environment `sin` implementing the sine function. The float slot is again a function environment and may be called like any MuPAD function. Note, however, the different functionality: in contrast to `sin`, the float slot always tries to compute a floating point approximation:

    >> s := slot(sin, "float"): s(1) , sin(1)

                               0.8414709848, sin(1)

With the following command, `s` becomes the function environment `sin` apart from a changed `"float"` slot. The `slot` call has no effect on the original `sin` function because `slot` returns a copy of the function environment:

    >> s := slot(sin, "float", x -> float(x - x^3/3!)):
       s(PI/3) = sin(PI/3), s::float(1) <> sin::float(1)

                      1/2    1/2
                     3      3
                     ---- = ----, 0.8333333333 <> 0.8414709848
                      2      2

    >> delete s:

#### Example 3

If you are using the `slot` function to change slot entries in a domain, you must be aware that you are modifying the domain. This is in contrast to changing slots of function environments (see example 2):

    >> old_one := slot(Dom::Float, "one")

                                        1.0

    >> newDomFloat := slot(Dom::Float, "one", 1):
       slot(newDomFloat, "one"), slot(Dom::Float, "one")

                                       1, 1

We restore the original state:

    >> slot(Dom::Float, "one", old_one): slot(Dom::Float, "one")

                                        1.0

    >> delete old_one, newDomFloat:

#### Example 4

The function environment `sin` does not contain a `"sign"` slot. So accessing this slot yields `FAIL`:

    >> slot(sin, "sign"), sin::sign

                                    FAIL, FAIL

#### Example 5

We define a function environment for a function computing the logarithm to the base `10`:

    >> log10 := funcenv(x -> log(10, x)):

If the function `info` is to give some information about `log10`, we have to define the `"info"` slot for this function. For function environments, `slot` returns a copy of the original object, so the result of the `slot` call has to be assigned to `log10`:

    >> log10 := slot(log10, "info",
                    "log10 -- the logarithm to the base 10"):

    >> info(log10)

          log10 -- the logarithm to the base 10

The `delete` statement is used for deleting a slot:

    >> delete log10::info: info(log10)

          Sorry, no information available.

It is not possible to delete the special slot `"dom"`:

    >> delete log10::dom

          Error: Illegal argument [delete]

    >> delete log10:

#### Example 6

Here we demonstrate the subtle difference between the `slot` function and the use of the `::`-operator in assignments. The following call adds a `"xyz"` slot to the domain `DOM_INT` of integer numbers:

    >> delete b: d := b: b := DOM_INT: slot(d, "xyz", 42):

The slot `"xyz"` of `DOM_INT` is changed, because `d` is fully evaluated with the result `DOM_INT`. Hence, the slot `DOM_INT::xyz` is set to 42:

    >> slot(d, "xyz") , slot(DOM_INT, "xyz")

                                      42, 42

Here is the result when using the `::`-operator: `d` is only evaluated with level 1, i.e., it is evaluated to the identifier `b`. However, there is no slot `b::xyz`, and an error occurs:

    >> delete b: d := b: b := DOM_INT: d::xyz := 42

          Error: Unknown slot "d::xyz" [slot]

    >> delete b, d:

#### Example 7

The first argument of `slot` is not flattened. This allows access to the slots of expression sequences and `null()` objects:

    >> slot((a, b), "dom"), slot(null(), "dom")

                                DOM_EXPR, DOM_NULL

#### Example 8

We give an example for the use of the function `make_slot`. The element `undefined` of the domain `stdlib::Undefined` represents an undefined value. Any function `f` should yield `f(undefined) = undefined`. Inside the implementation of `stdlib::Undefined`, we find:

    >> undef := newDomain("stdlib::Undefined"):
       undefined := new(undef):
       undef::func_call := proc() begin undefined end_proc;
       undef::make_slot := undef::func_call:

The following mechanism takes place automatically for a function `f` that is overloadable by its first argument: in the call `f(undefined)`, it is checked whether the slot `undef::f` exists. If this is not the case, the `make_slot` function creates this slot ``on the fly'', producing the value `undefined`. Thus, via overloading, `f(undefined)` returns the value `undefined`.

#### Example 9

The following example is rather advanced and technical. It demonstrates overloading of the `slot` function to implement slot access and slot assignments for other objects than domains (`DOM_DOMAIN`) or function environments (`DOM_FUNC_ENV`). The following example defines the slots `"numer"` and `"denom"` for rational numbers. The domain `DOM_RAT` of such numbers does not have slots `"numer"` and `"denom"`:

    >> domtype(3/4)

                                      DOM_RAT

    >> slot(3/4, "numer");

          Error: Unknown slot "(3/4)::numer" [slot]

We can change `DOM_RAT`, however. For this, we have to unprotect `DOM_RAT` temporarily:

    >> unprotect(DOM_RAT):
       _assign(DOM_RAT::slot,
         proc(r : DOM_RAT, n : DOM_STRING, v=null(): DOM_INT)
             local i : DOM_INT;
         begin
             i := contains(["numer", "denom"], n);
             if i = 0 then
                error("Unknown slot \"".expr2text(r)."::".n."\"")
             end;
             if args(0) = 3 then
                subsop(r, i = v)
             else
                op(r, i)
             end
         end_proc):

Now, we can access the operands of rational numbers, which are the numerator and the denominator respectively, via our new slots:

    >> slot(3/4, "numer"), (3/4)::numer,
       slot(3/4, "denom"), (3/4)::denom

                                    3, 3, 4, 4

    >> a := 3/4: slot(a, "numer", 7)

                                        7/4

    >> a::numer := 11: a

                                       11/4

We restore the original behaviour:

    >> delete DOM_RAT::slot, a: protect(DOM_RAT, Error):

#### Background

- Overloading of system functions by domain elements is typically implemented as follows. If a library function `f`, say, is to be overloadable by user defined data types, a code segment as indicated by the following lines is appropriate. It tests whether the domain `x::dom` of the argument `x` contains a method `f`. If this is the case, this domain method is called:

      f:= proc(x)
          begin
            // check if f is overloaded by x
            if x::dom::f <> FAIL then
                 // use the method of the domain of x
                 return(x::dom::f(args()))
            else
                 // execute the code for the function f
            endif
          end_proc:

- By overloading the function `slot`, slot access and slot assignment can be implemented for other objects than domains or function environments. Cf. example 9.
- In principle, the name `n` of a slot may be an arbitrary MuPAD object. Note, however, that the `::`-operator cannot access slots defined by `slot(d, n, v)` if the the name `n` is not a string.
- Strings may be used in conjunction with the `::`-operator: the calls `d::"n"` and `d::n` are equivalent.

#### Changes

- new function
- `slot` replaces and unifies the functions `domattr` and `funcattr` of previous MuPAD versions. The domain method `"make_slot"` works exactly as the former domain method `domattr`.

Do you have questions or comments?
Copyright © SciFace Software GmbH & Co. KG 2000