An irreverent yet positively innovative approach regarding data typing
I love programming. I discovered the computers and wrote my first programs when I was a kid and I've never stopped since then.
For some time now, I've been working on a Web App framework, and this led me to think about a lot of things, amongst which data typing.
It took me quite a long time to realize that the conventional approach of using variable types in most programming languages leads developers to create programs that require tremendous efforts to deal with validation, adaptation, storage and rendering of the manipulated values.
The reason is that traditional data typing in programs is very permissive, tends to prioritizes technical needs over human reasoning, often lacks of context validation, and is rarely explicit in terms of human representation.
This article presents a solution that aims to tackle these limitations by suggesting a more complete, flexible and unambiguous way to define and to handle data.
TL;DR
| If, when declaring... | You intend to deal with... |
|---|---|
let country:string | "a two letters code of a country that complies with ISO3166" |
float amount | "an amount of money with a precision of 4 decimal digits" |
string email | "an email address that complies with IETF RFC 5322 & RFC 6854" |
string password | "the blowfish encrypted version of a password complying with NIST recommendations" |
Then you're using an ambiguous typing and you probably have to manually deal with validations and conversions.
This article presents the advantages of using an explicit typing, and suggests that a simple syntax inspired by the ) for building such descriptors.
Using the MIME notation, in conjunction with concepts for which an unambiguous definition or an international standard exists, provides an explicit typing. For instance, we can assume that a "language" is a value that holds 2 or 3 lowercase letters and whose possible values are provided by the ISO standards ISO-639-1 and ISO-639-2.
The term "usage" is used to distinguish explicit types from primitive types.
Here is the full syntax of a "usage" descriptor:
type [ ["/" subtype[.variation][":" length]] ]["{" min, max "}"]
typeis the name of the non-primitive type;
subtypeis the mandatory categorization of the non-primitive type (example: number/integer). It always has a default value so it can be omitted (ex. text defaults to text/plain);
variation(optional) additional meta information to identify a specific standard or norm (example: hash/md.4);
lengthis either an amount of digits (or glyphs), or a length under the formprecision.scale;
- for numeric values, the length tells the amount of digits (required bytes can be found with
ceil(log2(x) / 8); - for strings, the length indicates the amount of glyphs (which might differ from the number of bytes);
- for usages that imply a floating point numbers, the length can be composed of several parts separated with dots (e.g.
precision[.scale]).
- for numeric values, the length tells the amount of digits (required bytes can be found with
minandmaxare optional parameters intended for numbers and can be used for defining custom limits. By default, there are always limits, set based on the min and max implied by the usage. If set, these values must be consistent with the length (for instance number/natural:2 cannot have a min lower than 0 nor a max higher than 99).
The primitive types can coexist, but become special cases of the "usage".
The proposition being that:
- A usage always relates to a generic type (by example, all variations of "number/real" relate to the type "float");
- All generic types are associated with one default usage;
- The default boundaries depend on the local environment and off-limit values should be rejected by it.
Examples
Below is presented a non-exhaustive list of descriptors using such notation.
| Usage | Primitive Type | Description | Examples | |
|---|---|---|---|---|
| TEXTS | ||||
| text/plain | string | A regular string composed of unicode chars (UTF-8 4-byte) Alias: text, text/plain.short, text/plain:255 Variations: text/plain.small (65KB) text/plain.medium (16MB), text/plain.long (4GB) | Hello world. | |
| text/xml | An XML formatted string (equivalent to MIME "application/xml") | <Person> <Name>Joe</Name> </Person> | ||
| text/html | An HTML formatted string. | <p>HTML rocks!</p> | ||
| text/markdown | A piece of text using MarkDown notation. | ## Title | ||
| text/wiki (markup/wikitext) | A piece of text using Wiki markup. | ''italic'' | ||
| NUMBERS | ||||
| amount/money | A financial amount Alias: amount/money:9.2, amount/money:2 Variations: amount/money:9.4 (FASAB/GAAP) | 886.90 EUR | ||
| amount/percent | A percentage Alias: amount/percent:2 | 85.13% | ||
| amount/rate | A rate amount (with no units). Alias: amount/rate:4 Variations: amount/rate:6 | 1.0789 | ||
| number/boolean | bool | Alias: number/boolean:1 | ||
| number/natural | A positive integer (ISO 80000-2: [0;99]) Alias: number/natural:9 (32bit) or number/natural:19 (64 bits) Example : number/natural:2 (2 digits positive integer) | 0, 25, 999 | ||
| number/integer | int | Alias: number, number/integer.decimal Variations: number/integer.hexadecimal, number/integer.octal Examples: number/integer:1 (a single digit integer: [-9;+9]) | -32767, 1, 65535 | |
| number/real | float | Alias: number/real:10.2 Example: number/real:5.2 (a float number with 2 decimal digits and max 3 digits for the integer part) | 123.45 | |
| URI | ||||
| url/mailto | A "mailto" URI (RFC6068) for writing a message to an email address. | |||
| url/ftp | A URL using FTP and FTPS scheme. | :00:00UTC]) Alias: date | 1955-11-05 | |
| date/time | A full ISO 8601 date holding an UTC time. Alias: datetime | 1955-11-13T05:04:00Z | ||
| date/year | Alias: date/year:4 (integer 0-9999) Variations: date/year:2 | 1999 | ||
| date/month | An integer representing a month within the year (ISO-8601 : 1 to 12, 1 being January) | 11 | ||
| date/weekday | An integer representing a day within the week (ISO-8601: 1 to 7, 1 being Monday) Alias: date/weekday.mon Variations: date/weekday.sun (0 to 6, 0 is Sunday) | 3 | ||
| date/monthday | An integer representing a day within the month (1-31) (ISO-8601) | 28 | ||
| date/yearweek | An integer representing a number of week within a year (1-52) | 51 | ||
| date/yearday | An integer representing a day within the year (1-365) (ISO-8601) | 130 | ||
| time/plain | An integer, representing the time of the day (number of seconds within range [0-86400], displayed as h:m:s) | 24200 | ||
| MISC | ||||
| A string describing an email address as defined by IETF RFC 5322 & RFC 6854 | ) Alias: language/iso-639:2 Variations : language/iso-639:3 () Alias: country/iso-3166:2 Variations: country/iso-3166:3 () | |||
| color/rgb | A color descriptor as a string with 3 integer values separated by commas. | 255,255,255 | ||
| color/rgba | A color descriptor as a string with 4 integer values separated by commas. | 255,128,255,0.8 | ||
| color/hexadecimal | A color descriptor as a string starting with '#', followed by 3 (#rgb), 6 (#rrggbb) or 8 (#rrggbbaa) hexadecimal characters. | #ffffff |
Numbers boundaries
When it comes to numbers, it is common for a variable not to relate to any standard or external convention, but instead to have boundaries (i.e. minimum and maximum possible values).
For that, we can use a notation similar to the one used in regular expressions for {n,m} quantifiers (
Valuable sources consulted over time
https://docs.oracle.com/javase/tutorial/essential/regex/
SOCIAL SHARE CARD GENERATOR