change the set method to put
Misty Programming Language:

Objects

Misty is an object-oriented language but it is not a classical language: Objects are not rigidly defined by classes. Instead, Misty's objects can be soft and malleable. Misty unifies objects and associative data structures. Objects are unordered containers of key/value pairs. Objects are passed by reference. Misty objects can have members added or removed at any time. Objects are mutable, but can be made immutable by the fix prefix operator. Members can be accessed using either a dot notation or a bracket notation.

Object Literal

A new object can be made with an object literal.

object_literal => '{' pair, '}'

pair
=> name [':' expression | parameter_list function_body]
=> text ':' expression

In the object literal notation, the specification of an object begins with { (left brace) and ends with } (right brace). Between them are zero or more name/value pairs, separated by , (comma). A name/value pair is an identifier or text, followed by : (colon) followed by an expression. (See JSON.) Each pair contributes a member to the object.

If the value is a function, then the abbreviated method form can be used. See Functions.

If no value is supplied, then the value is obtained from a variable with the same name.

An empty object can be made by {} (braces).

empty_object : {}    # empty_object is {}

color : {            # color is {
    aliceblue,       #     "aliceblue"    : aliceblue,
    antiquewhite,    #     "antiquewhite" : antiquewhite,
    aqua             #     "aqua"         : aqua
}                    # }

The statement:

stooge : {first : "Curly", last : "Howard"}

has the same result as

stooge : {}
stooge.first : "Curly"
stooge.last : "Howard"

Members

The members of an object can be accessed with either the dot notation or the subscript notation.

Dot notation

The dot notation is usually the most convenient notation for accessing the members of an object. It takes an object and an identifier.

Example:

stooge : {first : "Curly", last : "Howard"}
first_name : stooge.first      # first_name is "Curly"
first_name : null.first        # first_name is null
new_stooge : object stooge
new_stooge.first : "Shemp"     # new_stooge is {first : "Shemp"}
last_name : new_stooge.last    # last_name is "Howard"

Subscript notation

The subscript notation is similar to the dot notation, but instead of taking an identifier (which is used as a text) it can take an expression of any type except null. It can be used for dynamically making member names, or for creating keys which are not texts. Type is significant in keys. The key 0 (a number) is distinct from the key '0' (a text). A key 'a' (lower case) is distinct from a key 'A' (upper case). The subscript expression is wrapped in [ (left bracket) and ] (right bracket).

The subscript notation is used with objects, arrays, and texts. Using it with any other type raises a 'type' exception.

Example:

stooge : {first : "Curly", last : "Howard"}
first_name : stooge['first']    # first_name is "Curly"
new_stooge : object stooge
new_stooge['first'] : "Shemp"
    # new_stooge is {first : "Shemp"}
new_stooge['aka'] : "Samuel Horwitz"
    # new_stooge is {aka : "Samuel Horwitz", first : "Shemp"}

Operators

See Operators to see more about these operators.

can

The can operator returns true if its first operand is an object and if its first operand has a member that is a function that is named by the second operand.

fix

The fix prefix operator makes an object immutable. It is not possible to modify a fixed object.

has

The has operator returns true if its first operand is an object and if its first operand has a member that is named by the second operand.

is data

The is data operator returns true for objects.

is fix

The is fix operator returns true if its operand is immutable.

is object

The is object operator returns true for objects.

Sets

Objects can be used as sets. A set is an unordered collection of names. If we ignore the values in an object, the keys work just like a set. By convention, we use true as the value of members of a set but you can use any values you like except null. An array can be converted into a set object with array.object(true). The object.keys method can be used to turn a set object into an array.

The methods union, intersection, and difference create a new set from two existing sets. One of the sets is always an object. The other set can be an object, or an array that will be converted into a set object for you, or null which will be interpreted as the empty set.

Foreign Objects

A Misty system may be working in an environment that provides objects that work very differently than Misty's objects. Such foreign objects can be wrapped to act as Misty objects. Such objects will have three methods: get, set, and call.

Methods

The method invocation pattern is

object.method_name(parameter_list)

The object is searched for a member matching the method_name. If the result of that search is not a function, then the list of built-in function methods will be searched. This avoids conflicts in the use of data members that happen to have the same names as the methods. It is possible, for example, to use text as both a data member and a method.

define my_object : {text : "Carl Hollywood"}
result : my_object.text()
    # result is '{text: "Carl Hollywood"}'

These are the built-in methods. They are available to all objects except foreign objects. All of these methods may be overridden.

object.array(dimension, init)

Numbers can be used as keys, so objects can be used as sparse arrays. The array method can turn a sparse object into a normal array. It does this by first creating an array of a given size, with all of the elements initialized to the specified init value. Then every member in the object with an integer key that fits within the dimension is copied into the array.

It returns a new array.

object.combine(second)

The combine method takes all of the members of a second object and copies them in this object. If the second object contain members sharing the same keys, the new values replace the old ones in this object. If the first object is fixed, then a 'fix' exception will be raised. Also see the object.union method.

It returns the expanded, modified object.

object.difference(second)

The difference method treats the object as a set, producing the difference of the object and a second object or array.

It returns a new object containing all of the members of the object that do not have the same keys as members of second.

object.finalize(method)

The finalize method registers a finalization method with the object. Multiple finalization methods can be added to any object.

When the object is ready to be garbage collected, the finalization methods will be invoked. If a finalization method causes the program to become aware of the object, then the object will not be garbage collected, but all of its finalization methods will be removed.

It returns the object.

object.intersection(second)

The intersection method treats this object as a set, producing the intersection of this object and a second object or array.

It returns a new object containing the members of this object that have the same keys as members of the second.

object.keys()

The keys method makes an array containing all of the own keys in the object that are texts. The keys are not guaranteed to be in any particular order. If the object is fixed then it raises a 'fix' exception.

It returns an array of keys.

object.pretty()

The pretty method makes a text from the object, adding line breaks and indentations to make it more readable.

It returns a text.

object.remove(key)

The remove method removes the own member associated with the key from the object. If there is no member with a matching key, then nothing is removed. If key is an array, then it is treated as an array of keys that will all be removed from the object.

Changing a member's value to null will also remove it. Also see the object.difference method.

It returns the modified object.

object.text()

The text method makes an Extended JSON text from the object.

It returns a text.

object.union(second)

The union method treats the object as a set, producing the union of this object and a second object or array.

It returns a new object that contains all of the members of the object and the second object. Where the objects' keys intersect, this object's members will be used.

object.values(keys)

The values method returns an array containing the values of members of the object. keys is an array of keys (usually obtained from the object.keys method) The keys are used to determine the order of the values.

It returns an array of values.

Example:

o : {last: "Hollywood", first: "Carl"}
result : o.values(['first', 'last'])    # result is ["Carl", "Hollywood"]

Operator Methods

Binary operator Method
+ add
- subtract
* multiply
/ divide
^ raise
& concat
&&& concats
= equal
< lt
> gt
<= le
>= ge
apply apply
mod mod
min min
max max
Unary operator Method
+ number
- negate
~ text
abs abs
arity arity
int int
name name
not not
parameters parameters

Many of the unary and binary operators can be used on objects that contain suitable methods. For example, if myobject contains an add method, then

myobject + value

has the same result as

myobject.add(value)

Similarly,

-myobject

has the same result as

myobject.negate()

and

a <> b

has the same result as

not (a.equal(b))

This makes it possible to create specialized number types which use objects to implement special characteristics (such as bignum or complex) and to use those objects with the normal operators. Note that only two of these methods (text and equal) are implemented by default for objects.

Note that eq is always concerned with exactly the same object. It can be overridden. The = operator used on an object will call the equal method, which can be overridden.

$ will be bound to the first operand. Unary methods must have an arity of 0. Binary methods must have an arity of 1.

More on keys

Generally, texts are used as keys, but any value can be used as a key. Only texts can be used in object literals and with the . operator, but any value may be used with the [ ] operator. Only text keys are enumerated by the object.keys method.

An object key can be used to add a secret property to an object. The property value can only be obtained by presenting both objects.

An object key does not act as a memory root. If all references to a key are lost, then the property using the lost object as a key is deleted.

The Works

Get

The Misty machine uses a get procedure to retrieve values from an object.

If there is no key in the object that exactly matches the key specified in the dot notation or subscript notation (as determined by the be operator), then the result is null, not an error or exception. This makes it easy to query an object.

Call

The Misty machine uses a call procedure to retrieve function values from an object. The call procedure is similar to the get procedure with a couple of differences.

The call procedure is only interested in function values.

If the function is not found, it will look to the built-in methods.

The is function operator and the can operator use the call procedure rather than the get procedure.

Put

The Misty machine uses a put procedure to store values into an object. If the object is fixed, then a 'fix' exception is raised. If the key text already exists in the object, then the value is replaced. If the key text does not already exist in the object, the new key and value are added. If the value being stored is null, then the member is deleted.