# dict ## Description The native file format used by dictIO shares, by intention, some commonalities with the [OpenFOAM](https://www.openfoam.com/documentation/guides/latest/doc/openfoam-guide-input-types.html) file format, but is kept simpler and more tolerant to different flavours of string formatting. ## Structure The basic structure of a dict file consists of * header (block comment) [optional] * include directive(s) [optional] * key'd elements (each written as key value pair) As header and include directives are optional, in its simplest form a dict file can contain just a single key'd element: ~~~cpp var1 3.14159; ~~~ ## Header The default block comment used as header in dict files generated by dictIO looks as follows: ~~~cpp /*---------------------------------*- C++ -*----------------------------------*\ filetype dictionary; coding utf-8; version 0.1; local --; purpose --; \*----------------------------------------------------------------------------*/ ~~~ ## #include Directive(s) One of the most powerful features of dict files is their ability to be cascaded through the use of #include directives. An #include directive declares a (child) dict file to be merged into the (parent) dict when reading. This allows to separate i.e. a case agnostic configuration file from its case specific parameterization: While the core configuration dict is kept unchanged, case specific parameterization is accomplished by varying only the parameter dict. An #include directive consists of the #include statement followed by the path to the dict to be included: ~~~cpp #include 'a_paramDict_in_same_folder' #include 'subfolder/a_paramDict_in_subfolder' // Posix style with forward slashes is recommended (will work also on Windows) #include '../a_paramDict_in_parent_folder' #include 'subfolder\a_paramDict_in_subfolder' // also ok, but not recommended #include '..\a_paramDict_in_parent_folder' ~~~ ## Element Types The following element types are supported in dict files read and written by dictIO. The table also indicates to which Python data type they are casted when a dict file is read. | element type | example | (Python type) | | :------------ | :-------------------------------- | :---------------- | | boolean | true, false, on, off | bool | | number | 1, 1.0 | int, float | | none | None, none, NULL, null | None | | string | aString, 'a string', "a string" | str | | dict | {key1 value1; key2 value2;} | dict | | list | (1.0 2.0 3.0) | list | | reference | $var1 | (type of var1) | | expression | "$var1 + 4" | (type of var1) | ## Examples Below examples demonstrate the different element types supported by dictIO in dict files. ### booleans ~~~cpp bool1 true; // True bool2 false; // False bool3 True; // True bool4 False; // False bool5 on; // True bool6 off; // False bool7 ON; // True bool8 OFF; // False ~~~ ### numbers ~~~cpp int1 0; // int int2 120; // int float1 3.5; // float float2 1.00000000e+00; // float ~~~ ### nones ~~~cpp none1 None; // None none2 none; // None none3 NULL; // None none4 null; // None ~~~ ### strings ~~~js string1 ''; string2 'string'; string3 'string with spaces'; string4 singleWordsWithoutSpacesCanAlsoBeDeclaredWithoutQuotes; string5 'string with single quotes'; string6 "string with double quotes"; ~~~ ### dicts ~~~js emptyDict { } dictWithNumbers { var1 1; var2 2.0; var3 3.14; } dictWithStrings { string1 'string1'; string2 'string2 has spaces'; string3 'string3'; string4 'string4 is ok but note that string5 is empty'; string5 ''; } ~~~ ### lists ~~~js emptyList ( ); listWithNumbers ( 1 2.0 3.14 ); matrix // a matrix is represented by a list of lists ( (11 12 13) (21 22 23) (31 32 33) ); listWithStrings ( 'string1' 'string2 has spaces' 'string3' 'string4 is ok but note that string5 is empty' '' ); ~~~ ## References and Expressions Any key'd element in a dict file can also be treated as a variable that can be pointed to using references. A reference is denoted by a \$ character followed by the key of the element being referenced, also known as $keyword syntax. References, in turn, can be used inside expressions. Expressions are double-quoted strings containing a mathematical expression where at least one operand is a reference. Below code listing demonstrates the use of references and expressions: ~~~cpp varA 1.0; varB 2.0; list (1.0 2.0 3.0); matrix ( (11 12 13) (21 22 23) (31 32 33) ); reference1 $varA; // simple reference to a variable. References are prefixed with $. reference2 $list[0]; // indexed reference to an item in a list. reference3 $matrix[0]; // indexed reference to a specific row in a matrix (=returns a list). reference4 $matrix[0][1]; // indexed reference to a specific value in a matrix. expression1 "$varA"; // expression. However, result of this expression is same as using a simple reference without double quotes. expression2 "$varA + 4"; // expression with one reference and one constant. expression3 "$varA + $varB"; // expression with two references. expression4 "$list[0] + 3.14"; // expression with an indexed reference. ~~~ ## Nesting Both dicts and lists can be nested. In fact, dicts and lists in a dict file can be arbitrarily nested. While lexically possible, readability of nested data structures quickly suffers. In dict files intended to be read and edited by humans, such as configuration files, nesting should hence be used carefully and reasonably limited (an example that commonly causes misinterpretation is where a dict is nested inside a list, see section [The dict-in-a-list Pitfall](#the-dict-in-a-list-pitfall) further below). From a pure lexical / technical point of view, though, complex nesting of dicts and lists is possible. So, in cases where dict files are written and read purely by machines, this can provide additional capabilities. ~~~cpp nesting { emptyNestedDict { } emptyNestedList ( ); nestedDictWithNestedList { list1 ( 1.00000000e+00 2.20972831e-17 3.15717747e-18 ); list2 ( 2.20972831e-17 1.00000000e+00 -7.07290050e-18 ); list3 ( 3.15717747e-18 -7.07290050e-18 1.00000000e+00 ); } nestedListWithNestedList ( ( 1.00000000e+00 2.20972831e-17 3.15717747e-18 ) ( 2.20972831e-17 1.00000000e+00 -7.07290050e-18 ) ( 3.15717747e-18 -7.07290050e-18 1.00000000e+00 ) ); nestedListWithNestedDict ( ( 11 12 13 ) { value21 21; value22 22; value23 23; } ( 31 32 33 ) ); } ~~~ ## The dict-in-a-list Pitfall A very prominent example where nesting of dicts and lists deteriorates human readibility and causes misinterpretation is where a dict is nested inside a list. Read below example to see why: ~~~cpp keyToADict // This is a key. You can access its value (the subsequent dict {}) as a key'd element -> myDict['keyToADict'] { // This is the key'd element associated with key 'keyToADict'. It is of type dict. keyToAList // This is a key. You can access its value (the subsequent list ()) as a key'd element -> myDict['keyToADict']['keyToAList'] ( // This is the key'd element associated with key 'keyToAList'. It is of type list. notAKey // This is NOT a key. It is a list element of type string. You can access it by its index -> myDict['keyToADict']['keyToAList'][0] { // This is NOT a key'd element. It is a list element of type dict. You can access it by its index -> myDict['keyToADict']['keyToAList'][1] key1 value1; // This is a key'd element inside the surrounding dict -> myDict['keyToADict']['keyToAList'][1]['key1'] key2 value2; // This is a key'd element inside the surrounding dict -> myDict['keyToADict']['keyToAList'][1]['key2'] } notAKey // another list element -> myDict['keyToADict']['keyToAList'][2] notAKey // yet another list element -> myDict['keyToADict']['keyToAList'][3] notAKey // yet .. well, you got the point .. -> myDict['keyToADict']['keyToAList'][4] notAKey // NOT A KEY !! -> myDict['keyToADict']['keyToAList'][5] { // another list element of type dict -> myDict['keyToADict']['keyToAList'][6] key1 value1; // This is a key'd element inside the surrounding dict -> myDict['keyToADict']['keyToAList'][6]['key1'] key2 value2; // This is a key'd element inside the surrounding dict -> myDict['keyToADict']['keyToAList'][6]['key2'] } ); } ~~~