map - r3n/rebol-wiki GitHub Wiki

This document describes the new map datatype.

Table of Contents

Overview

A map is a key-to-value associative array. It uses hashing for high performance. Sometimes this kind of association is also referred to as a dictionary.

The map datatype replaces the R2 hash datatype. The motivation for this replacement was that some people in the user community felt the design of the older hash datatype was confusing, since it hashed both keys and their data. The new map datatype just hashes keys. Data is not hashed.

Keys

The map datatype lets you attach keys to data values. It is more efficient than a block or object (when words as keys are unbound) once you have more than a couple dozen keys.

A key can be any type of word or string. Other datatypes are not allowed at this time.

Note that when a string is used for a key:

  • the dataype of the string is also part of the key. For example, the string "test" is not the same as the file name %test or the issue #test.
  • the string is copied into the map. It is not by reference. This prevents the problem where a string is modified after the association has been made.
Map allows integers as keys. They are not indexes.
>> m: make map! [x a 1 b 2 c 3 y]
== make map! [x a 1 b 2 c 3 y]
>> m/2
== c

Values

The value associated with a key can be any datatype. For example, you can associate a key that happens to be a word with a file name, a block, an object, or even a graphics object.

Note that series and other complex datatype values are stored by reference. That means that they can be modified outside of the map structure.

Actions

You can access a map using paths or action functions.

The paths allowed are:

  • dict/word - get a value for that key (or return NONE if no such word)
  • dict/word: - set a value for that key, or creating it if necessary
These action functions are currently supported:
  • make
  • to
  • pick
  • select (same as pick)
  • poke
  • length
  • equal?
  • not-equal?
  • append
  • insert (same as append)
In addition TO-BLOCK, TO-OBJECT, FORM and MOLD will work for map types.

General Usage

General usage has been kept very simple -- to be on par (or better) with what other scripting languages offer.

Here is an example that shows the most common usage patterns:

d: make map! 1000

d/test: 10
print d/test
10

print d/notest
none

d/test: 20
print d/test
20

The above example shows that you can directly create new map keys and values.

Also, you can see that if a key is not defined in the map, a NONE value is returned.

The PICK and POKE series functions also allow access to the map:

poke d 'test 100
print pick d 'test
100

PICK and POKE are also necessary when strings are used as keys:

poke d "text" [1 2 3 4]
poke d %file 1234
print pick d "text"
1 2 3 4
print pick d %file
1234
print pick d "file"
none

That last case is used to show that the datatype of strings is part of the key when using maps.

Note that instead of PICK and POKE it's also possible to use path evaluation:

key: "id"
d/(key): 5678
print d/(key)
5678
key: 'id
d/(key): 9
print d/id
; == 9

keys: [name job]
d/(keys/1): "Carl"
d/(keys/2): "Guru"
print reduce [d/name "is" d/job]
; == Carl is Guru

Make Map

You can make a map with:

d: make map! 1000

or with:

d1: make map! [a: 10 b: 20 c: 30]

and, the word values do not need to be set-words. This also works:

d2: make map! [a 10 b 20 c 30]

In fact, Rebol will always preserve the datatype of the word, so if you MOLD d1 you will see:

make map! [a: 10 b: 20 c: 30]

But, d2 will give you:

make map! [a 10 b 20 c 30]

Notes

  1. Dictionaries auto-expand as needed. Once the hash table hits certain sizes, it also expands to keep hash key lookup fast.
  2. A map only becomes hashed after 16 keys are defined. This is done to keep very small dictionaries small with fast access.
  3. Keys are never removed from a map, for now. However, you can set a key to NONE if you no longer need it. The key will no longer appear when the map is formed or molded, and will not be included when the map is converted to a block or object. This is effectively the same thing as removing the key, except it still takes space in the map, for now.
  4. Dictionaries can not be used as series at this time (we may decide to add that later, but the concepts don't match). However, you can use TO-BLOCK to convert a map to a block series.
  5. Keys are not case sensitive (but, should there be a mode to allow that?)
  6. Currently, there is a maximum limit of about 500000 entries in a map. We can expand this limit if we think it's needed.
⚠️ **GitHub.com Fallback** ⚠️