[{"data":1,"prerenderedAt":1604},["ShallowReactive",2],{"content-\u002Freference\u002F0.4.x\u002Ftype-system":3,"use-cases-nav":1597},{"id":4,"title":5,"author":6,"body":7,"date":6,"description":1589,"extension":1590,"meta":1591,"navigation":234,"order":84,"path":1592,"seo":1593,"stem":1594,"version":1595,"__hash__":1596},"content\u002Freference\u002F0.4.x\u002Ftype-system.md","Type System",null,{"type":8,"value":9,"toc":1569},"minimark",[10,33,62,71,106,111,114,156,160,163,180,184,190,205,215,244,248,251,288,291,342,345,351,384,389,399,452,459,523,530,534,540,610,624,628,631,656,659,678,682,685,705,709,712,732,755,759,762,790,794,808,837,840,883,890,913,917,924,941,958,961,983,993,1003,1007,1010,1038,1041,1044,1069,1072,1097,1101,1104,1149,1152,1184,1187,1245,1248,1290,1293,1347,1388,1392,1399,1458,1470,1478,1482,1492,1526,1533,1565],[11,12,13,17,18,21,22,25,26,29,30,32],"p",{},[14,15,16],"em",{},"Finitio","'s type system is different from those you can find in a programming\nlanguage. The aim here is to capture ",[14,19,20],{},"information",", not software ",[14,23,24],{},"behavior",".\nTherefore, the definition of ",[14,27,28],{},"type"," differs. In ",[14,31,16],{},", a type is a set of\nvalues, a subtype is a subset, a supertype is a superset. That's it.",[11,34,35,36,40,41,45,46,49,50,53,54,57,58,61],{},"However, the aim here is ",[37,38,39],"strong",{},"not"," to define yet another type system with a\nfixed set of available types such as ",[42,43,44],"code",{},"boolean",", ",[42,47,48],{},"string"," and ",[42,51,52],{},"integer",", but\nrather to provide an abstract way of building ",[14,55,56],{},"information types"," and to\n'connect' them to the types available in a ",[14,59,60],{},"host"," programming language, or\ndata exchange language.",[11,63,64,65,67,68,70],{},"For this, a ",[14,66,16],{}," implementation has to define a representation function\nthat maps, for each ",[14,69,16],{}," type, a type of the host language that will\nrepresent values of the information type. This representation function is\nhost\u002Fimplementation-specific; see the documentation of the binding you use.",[72,73,78],"pre",{"className":74,"code":75,"language":76,"meta":77,"style":77},"language-finitio shiki shiki-themes github-light github-dark","Rep(FinitioType) -> HostType\n","finitio","",[42,79,80],{"__ignoreMap":77},[81,82,85,89,93,96,99,103],"span",{"class":83,"line":84},"line",1,[81,86,88],{"class":87},"sj4cs","Rep",[81,90,92],{"class":91},"sVt8B","(",[81,94,95],{"class":87},"FinitioType",[81,97,98],{"class":91},") ",[81,100,102],{"class":101},"szBVR","->",[81,104,105],{"class":87}," HostType\n",[107,108,110],"h2",{"id":109},"what-changed-in-04","What changed in 0.4",[11,112,113],{},"If you are coming from 0.3, two things are new and one moved:",[115,116,117,140,148],"ul",{},[118,119,120,45,123,45,126,129,130,135,136,139],"li",{},[42,121,122],{},"String",[42,124,125],{},"Integer",[42,127,128],{},"Date"," and friends are no longer builtin. They live in\nthe ",[131,132,134],"a",{"href":133},"\u002Freference\u002F0.4.x\u002Fstdlib","standard library"," and a schema brings them in\nwith ",[42,137,138],{},"@import finitio\u002Fdata",". Almost every 0.4 schema starts with that line.",[118,141,142,143,147],{},"Schemas can be split across files and reused through\n",[131,144,146],{"href":145},"\u002Freference\u002F0.4.x\u002Fimports","imports",".",[118,149,150,151,155],{},"Types can take type parameters — see ",[131,152,154],{"href":153},"#generic-types","generic types"," below.",[107,157,159],{"id":158},"any-type","Any type",[11,161,162],{},"Any type captures the set of all possible 'values' representable in the\nhost language. It is mostly provided for the sake of completeness and some\nimplementation needs by specific bindings. It is occasionally useful in\n\"don't care\" situations too. Any is captured by a single dot:",[72,164,166],{"className":74,"code":165,"language":76,"meta":77,"style":77},"Any = .\n",[42,167,168],{"__ignoreMap":77},[81,169,170,174,177],{"class":83,"line":84},[81,171,173],{"class":172},"sScJk","Any",[81,175,176],{"class":101}," =",[81,178,179],{"class":87}," .\n",[107,181,183],{"id":182},"builtin-types","Builtin types",[11,185,186,187,189],{},"A builtin type starts with a dot followed by the name of an abstraction in the\nhost language, a Ruby class or a JavaScript constructor for instance. The set\nof values captured by the ",[14,188,16],{}," type is the same set as the host\nabstraction. For instance,",[72,191,193],{"className":74,"code":192,"language":76,"meta":77,"style":77},".Integer  # The set of values captured by the Integer class\n",[42,194,195],{"__ignoreMap":77},[81,196,197,199,201],{"class":83,"line":84},[81,198,147],{"class":91},[81,200,125],{"class":87},[81,202,204],{"class":203},"sJ8bj","  # The set of values captured by the Integer class\n",[11,206,207,208,210,211,214],{},"To avoid builtins being spread everywhere, it is usual to define type aliases\nand build higher-level types with those aliases instead. This also provides\nbetter host-language independence and interoperability. That is exactly what\nthe standard library does, and why you should normally write ",[42,209,125],{}," rather\nthan ",[42,212,213],{},".Integer",":",[72,216,218],{"className":74,"code":217,"language":76,"meta":77,"style":77},"@import finitio\u002Fdata\n\nInteger   # from the standard library, host-independent\n",[42,219,220,229,236],{"__ignoreMap":77},[81,221,222,225],{"class":83,"line":84},[81,223,224],{"class":101},"@import",[81,226,228],{"class":227},"sZZnC"," finitio\u002Fdata\n",[81,230,232],{"class":83,"line":231},2,[81,233,235],{"emptyLinePlaceholder":234},true,"\n",[81,237,239,241],{"class":83,"line":238},3,[81,240,125],{"class":87},[81,242,243],{"class":203},"   # from the standard library, host-independent\n",[107,245,247],{"id":246},"sub-types","Sub types",[11,249,250],{},"Sub types are subsets of values. Finitio uses so-called 'specialization by\nconstraint' to define sub types. E.g., the set of positive integers can be\ndefined as follows:",[72,252,254],{"className":74,"code":253,"language":76,"meta":77,"style":77},"Posint = Integer( i | i >= 0 )\n",[42,255,256],{"__ignoreMap":77},[81,257,258,261,263,266,269,273,276,279,282,285],{"class":83,"line":84},[81,259,260],{"class":172},"Posint",[81,262,176],{"class":101},[81,264,265],{"class":87}," Integer",[81,267,268],{"class":91},"( ",[81,270,272],{"class":271},"s4XuR","i",[81,274,275],{"class":101}," |",[81,277,278],{"class":91}," i ",[81,280,281],{"class":101},">=",[81,283,284],{"class":87}," 0",[81,286,287],{"class":91}," )\n",[11,289,290],{},"Multiple constraints can be distinguished by name:",[72,292,294],{"className":74,"code":293,"language":76,"meta":77,"style":77},"Evens = Integer( i | positive: i >= 0, even: i%2 == 0 )\n",[42,295,296],{"__ignoreMap":77},[81,297,298,301,303,305,307,309,311,314,317,319,321,323,326,329,332,335,338,340],{"class":83,"line":84},[81,299,300],{"class":172},"Evens",[81,302,176],{"class":101},[81,304,265],{"class":87},[81,306,268],{"class":91},[81,308,272],{"class":271},[81,310,275],{"class":101},[81,312,313],{"class":172}," positive",[81,315,316],{"class":91},": i ",[81,318,281],{"class":101},[81,320,284],{"class":87},[81,322,45],{"class":91},[81,324,325],{"class":172},"even",[81,327,328],{"class":91},": i",[81,330,331],{"class":101},"%",[81,333,334],{"class":87},"2",[81,336,337],{"class":101}," ==",[81,339,284],{"class":87},[81,341,287],{"class":91},[11,343,344],{},"Naming a constraint is worth the few extra characters: a failure reports the\nname of the rule that was broken rather than a bare \"invalid value\".",[11,346,347,348,350],{},"All types can be sub-typed through constraints. In addition, Finitio uses\nstructural type equivalence, which means that the type captured by the\ndefinition of ",[42,349,300],{}," above is actually equivalent to the following one:",[72,352,354],{"className":74,"code":353,"language":76,"meta":77,"style":77},"Evens = Posint( i | i % 2 == 0 )\n",[42,355,356],{"__ignoreMap":77},[81,357,358,360,362,365,367,369,371,373,375,378,380,382],{"class":83,"line":84},[81,359,300],{"class":172},[81,361,176],{"class":101},[81,363,364],{"class":87}," Posint",[81,366,268],{"class":91},[81,368,272],{"class":271},[81,370,275],{"class":101},[81,372,278],{"class":91},[81,374,331],{"class":101},[81,376,377],{"class":87}," 2",[81,379,337],{"class":101},[81,381,284],{"class":87},[81,383,287],{"class":91},[385,386,388],"h3",{"id":387},"constraint-expressions-are-host-language-code","Constraint expressions are host-language code",[11,390,391,392,395,396,398],{},"The expression to the right of the ",[42,393,394],{},"|"," is ",[37,397,39],{}," Finitio. It is an\nexpression of the host language, evaluated there, and it is the one place\nwhere a schema can stop being portable.",[72,400,402],{"className":74,"code":401,"language":76,"meta":77,"style":77},"String( s | s.length > 0 )   # works in Ruby and in JavaScript\nString( s | s.size > 0 )     # Ruby only — JavaScript strings have no .size\n",[42,403,404,429],{"__ignoreMap":77},[81,405,406,408,410,413,415,418,421,423,426],{"class":83,"line":84},[81,407,122],{"class":87},[81,409,268],{"class":91},[81,411,412],{"class":271},"s",[81,414,275],{"class":101},[81,416,417],{"class":91}," s.length ",[81,419,420],{"class":101},">",[81,422,284],{"class":87},[81,424,425],{"class":91}," )   ",[81,427,428],{"class":203},"# works in Ruby and in JavaScript\n",[81,430,431,433,435,437,439,442,444,446,449],{"class":83,"line":231},[81,432,122],{"class":87},[81,434,268],{"class":91},[81,436,412],{"class":271},[81,438,275],{"class":101},[81,440,441],{"class":91}," s.size ",[81,443,420],{"class":101},[81,445,284],{"class":87},[81,447,448],{"class":91}," )     ",[81,450,451],{"class":203},"# Ruby only — JavaScript strings have no .size\n",[11,453,454,455,458],{},"The gap widens as soon as a constraint reaches into a tuple, because a tuple\nis a ",[42,456,457],{},"Hash"," in Ruby and a plain object in JavaScript:",[72,460,462],{"className":74,"code":461,"language":76,"meta":77,"style":77},"{ a: Integer, b: Integer }( t | t.a \u003C t.b )      # JavaScript\n{ a: Integer, b: Integer }( t | t[:a] \u003C t[:b] )  # Ruby\n",[42,463,464,496],{"__ignoreMap":77},[81,465,466,469,471,474,476,479,482,484,487,490,493],{"class":83,"line":84},[81,467,468],{"class":91},"{ a: ",[81,470,125],{"class":87},[81,472,473],{"class":91},", b: ",[81,475,125],{"class":87},[81,477,478],{"class":91}," }( ",[81,480,481],{"class":271},"t",[81,483,275],{"class":101},[81,485,486],{"class":91}," t.a ",[81,488,489],{"class":101},"\u003C",[81,491,492],{"class":91}," t.b )      ",[81,494,495],{"class":203},"# JavaScript\n",[81,497,498,500,502,504,506,508,510,512,515,517,520],{"class":83,"line":231},[81,499,468],{"class":91},[81,501,125],{"class":87},[81,503,473],{"class":91},[81,505,125],{"class":87},[81,507,478],{"class":91},[81,509,481],{"class":271},[81,511,275],{"class":101},[81,513,514],{"class":91}," t[:a] ",[81,516,489],{"class":101},[81,518,519],{"class":91}," t[:b] )  ",[81,521,522],{"class":203},"# Ruby\n",[11,524,525,526,529],{},"There is no portable spelling for that second example. If a schema has to run\nunder both bindings, keep constraints to simple comparisons on scalars, where\n",[42,527,528],{},".length",", arithmetic and the usual operators behave the same.",[385,531,533],{"id":532},"constraint-shortcuts","Constraint shortcuts",[11,535,536,537,214],{},"A few common constraints have a shorthand, introduced by ",[42,538,539],{},"::",[72,541,543],{"className":74,"code":542,"language":76,"meta":77,"style":77},"Slug   = String :: \u002F^[a-z0-9-]+$\u002F\nRating = Integer :: 1..10\nSuit   = String :: { \"hearts\" \"diamonds\" \"clubs\" \"spades\" }\n",[42,544,545,563,583],{"__ignoreMap":77},[81,546,547,550,553,556,559],{"class":83,"line":84},[81,548,549],{"class":172},"Slug",[81,551,552],{"class":101},"   =",[81,554,555],{"class":87}," String",[81,557,558],{"class":91}," :: ",[81,560,562],{"class":561},"sA_wV","\u002F^[a-z0-9-]+$\u002F\n",[81,564,565,568,570,572,574,577,580],{"class":83,"line":231},[81,566,567],{"class":172},"Rating",[81,569,176],{"class":101},[81,571,265],{"class":87},[81,573,558],{"class":91},[81,575,576],{"class":87},"1",[81,578,579],{"class":91},"..",[81,581,582],{"class":87},"10\n",[81,584,585,588,590,592,595,598,601,604,607],{"class":83,"line":238},[81,586,587],{"class":172},"Suit",[81,589,552],{"class":101},[81,591,555],{"class":87},[81,593,594],{"class":91}," :: { ",[81,596,597],{"class":227},"\"hearts\"",[81,599,600],{"class":227}," \"diamonds\"",[81,602,603],{"class":227}," \"clubs\"",[81,605,606],{"class":227}," \"spades\"",[81,608,609],{"class":91}," }\n",[611,612,614],"impl-note",{"impl":613},"finitio.js",[11,615,616,617,619,620,623],{},"finitio-rb does not parse ",[42,618,539],{},". Write the constraint in its long form\ninstead — ",[42,621,622],{},"String( s | \u002F^[a-z0-9-]+$\u002F.test(s) )"," — remembering that the body\nis host-language code.",[107,625,627],{"id":626},"union-types","Union types",[11,629,630],{},"In some respect, union types are the dual of subtypes. They allow defining new\ntypes by generalization, through the union of the sets of values defined by\nother types. For instance, the missing Boolean type of Ruby is simply captured\nas:",[72,632,634],{"className":74,"code":633,"language":76,"meta":77,"style":77},"Boolean = .TrueClass|.FalseClass\n",[42,635,636],{"__ignoreMap":77},[81,637,638,641,643,646,649,651,653],{"class":83,"line":84},[81,639,640],{"class":172},"Boolean",[81,642,176],{"class":101},[81,644,645],{"class":91}," .",[81,647,648],{"class":87},"TrueClass",[81,650,394],{"class":101},[81,652,147],{"class":91},[81,654,655],{"class":87},"FalseClass\n",[11,657,658],{},"Union types are also very useful for capturing possibly missing information\n(aka NULL\u002Fnil). For instance, the following type will capture either an\ninteger or nil:",[72,660,662],{"className":74,"code":661,"language":76,"meta":77,"style":77},"MaybeInt = Integer|Nil\n",[42,663,664],{"__ignoreMap":77},[81,665,666,669,671,673,675],{"class":83,"line":84},[81,667,668],{"class":172},"MaybeInt",[81,670,176],{"class":101},[81,672,265],{"class":87},[81,674,394],{"class":101},[81,676,677],{"class":87},"Nil\n",[107,679,681],{"id":680},"seq-types","Seq types",[11,683,684],{},"Capturing sequences (aka arrays) of values is straightforward. Sequences are\nordered and may contain duplicates:",[72,686,688],{"className":74,"code":687,"language":76,"meta":77,"style":77},"Measures = [Posint]\n",[42,689,690],{"__ignoreMap":77},[81,691,692,695,697,700,702],{"class":83,"line":84},[81,693,694],{"class":172},"Measures",[81,696,176],{"class":101},[81,698,699],{"class":91}," [",[81,701,260],{"class":87},[81,703,704],{"class":91},"]\n",[107,706,708],{"id":707},"set-types","Set types",[11,710,711],{},"Capturing sets of values is straightforward too. Sets are unordered and may\nnot contain duplicates:",[72,713,715],{"className":74,"code":714,"language":76,"meta":77,"style":77},"Hobbies = {String}\n",[42,716,717],{"__ignoreMap":77},[81,718,719,722,724,727,729],{"class":83,"line":84},[81,720,721],{"class":172},"Hobbies",[81,723,176],{"class":101},[81,725,726],{"class":91}," {",[81,728,122],{"class":87},[81,730,731],{"class":91},"}\n",[611,733,734],{"impl":613},[11,735,736,737,49,740,743,744,49,747,750,751,754],{},"Write ",[42,738,739],{},"[Posint]",[42,741,742],{},"{String}"," without a space after the opening bracket.\nfinitio-rb's grammar rejects ",[42,745,746],{},"[ Posint ]",[42,748,749],{},"{ String }",". Tuples are\nunaffected: ",[42,752,753],{},"{ name: String }"," parses everywhere.",[107,756,758],{"id":757},"struct-types","Struct types",[11,760,761],{},"Capturing structs is straightforward too. Structs can be used to capture\nordered pairs, triples, and so forth. Each struct component has its own type:",[72,763,765],{"className":74,"code":764,"language":76,"meta":77,"style":77},"Signature = \u003CString, Posint, Boolean>\n",[42,766,767],{"__ignoreMap":77},[81,768,769,772,774,777,779,781,783,785,787],{"class":83,"line":84},[81,770,771],{"class":172},"Signature",[81,773,176],{"class":101},[81,775,776],{"class":91}," \u003C",[81,778,122],{"class":87},[81,780,45],{"class":91},[81,782,260],{"class":87},[81,784,45],{"class":91},[81,786,640],{"class":87},[81,788,789],{"class":91},">\n",[107,791,793],{"id":792},"tuple-multi-tuple-types","Tuple & Multi-Tuple types",[11,795,796,797,800,801,804,805,147],{},"Tuples capture information facts. Unlike structs, tuples have ",[14,798,799],{},"named","\ncomponents called 'attributes'. Attributes must all have different names and\nare not particularly ordered. A set of such ",[42,802,803],{},"(name,Type)"," pairs is called a\n",[14,806,807],{},"heading",[72,809,811],{"className":74,"code":810,"language":76,"meta":77,"style":77},"ProgrammingLanguage = { name: String, author: String, since: Date }\n",[42,812,813],{"__ignoreMap":77},[81,814,815,818,820,823,825,828,830,833,835],{"class":83,"line":84},[81,816,817],{"class":172},"ProgrammingLanguage",[81,819,176],{"class":101},[81,821,822],{"class":91}," { name: ",[81,824,122],{"class":87},[81,826,827],{"class":91},", author: ",[81,829,122],{"class":87},[81,831,832],{"class":91},", since: ",[81,834,128],{"class":87},[81,836,609],{"class":91},[11,838,839],{},"Attributes may be separated by commas or simply by newlines:",[72,841,843],{"className":74,"code":842,"language":76,"meta":77,"style":77},"ProgrammingLanguage = {\n  name   : String\n  author : String\n  since  : Date\n}\n",[42,844,845,854,862,869,878],{"__ignoreMap":77},[81,846,847,849,851],{"class":83,"line":84},[81,848,817],{"class":172},[81,850,176],{"class":101},[81,852,853],{"class":91}," {\n",[81,855,856,859],{"class":83,"line":231},[81,857,858],{"class":91},"  name   : ",[81,860,861],{"class":87},"String\n",[81,863,864,867],{"class":83,"line":238},[81,865,866],{"class":91},"  author : ",[81,868,861],{"class":87},[81,870,872,875],{"class":83,"line":871},4,[81,873,874],{"class":91},"  since  : ",[81,876,877],{"class":87},"Date\n",[81,879,881],{"class":83,"line":880},5,[81,882,731],{"class":91},[11,884,885,886,889],{},"By default, all attributes are mandatory. It is very useful in practice to\nallow optional attributes too. Multi-tuples provide such support.\nMulti-tuples are a very convenient shorthand over unions of tuple types. For\ninstance, the multi-tuple type below allows ",[42,887,888],{},"since"," to be omitted:",[72,891,893],{"className":74,"code":892,"language":76,"meta":77,"style":77},"{ name: String, author: String, since :? Date }\n",[42,894,895],{"__ignoreMap":77},[81,896,897,900,902,904,906,909,911],{"class":83,"line":84},[81,898,899],{"class":91},"{ name: ",[81,901,122],{"class":87},[81,903,827],{"class":91},[81,905,122],{"class":87},[81,907,908],{"class":91},", since :? ",[81,910,128],{"class":87},[81,912,609],{"class":91},[385,914,916],{"id":915},"extra-attributes","Extra attributes",[11,918,919,920,923],{},"By default a tuple rejects any attribute it does not declare. A trailing\n",[42,921,922],{},"..."," accepts them instead:",[72,925,927],{"className":74,"code":926,"language":76,"meta":77,"style":77},"{ name: String, ... }\n",[42,928,929],{"__ignoreMap":77},[81,930,931,933,935,937,939],{"class":83,"line":84},[81,932,899],{"class":91},[81,934,122],{"class":87},[81,936,45],{"class":91},[81,938,922],{"class":101},[81,940,609],{"class":91},[11,942,943,944,947,948,954,955,957],{},"Such a tuple accepts ",[42,945,946],{},"{\"name\": \"Finitio\", \"age\": 44}"," — but ",[37,949,950,953],{},[42,951,952],{},"age"," does not\nsurvive dressing",". Finitio's purpose is to give guarantees about data, and\n",[42,956,922],{}," states nothing at all about those attributes, so there is nothing to\nvouch for and they are dropped.",[11,959,960],{},"Give the extra attributes a type and they are kept, because now there is a\nguarantee to make:",[72,962,964],{"className":74,"code":963,"language":76,"meta":77,"style":77},"{ name: String, ...: Integer }\n",[42,965,966],{"__ignoreMap":77},[81,967,968,970,972,974,976,979,981],{"class":83,"line":84},[81,969,899],{"class":91},[81,971,122],{"class":87},[81,973,45],{"class":91},[81,975,922],{"class":101},[81,977,978],{"class":91},": ",[81,980,125],{"class":87},[81,982,609],{"class":91},[11,984,985,986,988,989,992],{},"Dressing ",[42,987,946],{}," against that type yields both\nattributes, and ",[42,990,991],{},"{\"name\": \"Finitio\", \"age\": \"forty-four\"}"," is rejected.",[11,994,995,996,999,1000,1002],{},"Note that ",[42,997,998],{},"...: ."," behaves like a bare ",[42,1001,922],{},": the Any type constrains\nnothing, so it guarantees nothing.",[107,1004,1006],{"id":1005},"relation-multi-relation-types","Relation & Multi-relation types",[11,1008,1009],{},"Relations are sets of tuples, all of which have the same heading. The notation\nfor defining relation types naturally follows:",[72,1011,1013],{"className":74,"code":1012,"language":76,"meta":77,"style":77},"Languages = {{ name: String, author: String, since: Date }}\n",[42,1014,1015],{"__ignoreMap":77},[81,1016,1017,1020,1022,1025,1027,1029,1031,1033,1035],{"class":83,"line":84},[81,1018,1019],{"class":172},"Languages",[81,1021,176],{"class":101},[81,1023,1024],{"class":91}," {{ name: ",[81,1026,122],{"class":87},[81,1028,827],{"class":91},[81,1030,122],{"class":87},[81,1032,832],{"class":91},[81,1034,128],{"class":87},[81,1036,1037],{"class":91}," }}\n",[11,1039,1040],{},"Relation types and their syntax are first-class in Finitio, most notably\nbecause of the availability of relational algebra for them, unlike pure sets\nof tuples.",[11,1042,1043],{},"Note that relations do not allow duplicates and have no significant ordering\nof their tuples. If the ordering is significant, you should consider a\nsequence of tuples instead:",[72,1045,1047],{"className":74,"code":1046,"language":76,"meta":77,"style":77},"Preferences = [{ lang: String, reason: String }]\n",[42,1048,1049],{"__ignoreMap":77},[81,1050,1051,1054,1056,1059,1061,1064,1066],{"class":83,"line":84},[81,1052,1053],{"class":172},"Preferences",[81,1055,176],{"class":101},[81,1057,1058],{"class":91}," [{ lang: ",[81,1060,122],{"class":87},[81,1062,1063],{"class":91},", reason: ",[81,1065,122],{"class":87},[81,1067,1068],{"class":91}," }]\n",[11,1070,1071],{},"Similarly to tuples, multi-relations allow optional attributes. For instance,",[72,1073,1075],{"className":74,"code":1074,"language":76,"meta":77,"style":77},"Languages = {{ name: String, author: String, since :? Date }}\n",[42,1076,1077],{"__ignoreMap":77},[81,1078,1079,1081,1083,1085,1087,1089,1091,1093,1095],{"class":83,"line":84},[81,1080,1019],{"class":172},[81,1082,176],{"class":101},[81,1084,1024],{"class":91},[81,1086,122],{"class":87},[81,1088,827],{"class":91},[81,1090,122],{"class":87},[81,1092,908],{"class":91},[81,1094,128],{"class":87},[81,1096,1037],{"class":91},[107,1098,1100],{"id":1099},"generic-types","Generic types",[11,1102,1103],{},"A type definition can take type parameters, so one shape can serve many\npayloads. Parameters are declared between angle brackets after the name, and\nused in the body like any other type:",[72,1105,1107],{"className":74,"code":1106,"language":76,"meta":77,"style":77},"Page\u003CT> = {\n  items : [T],\n  total : Integer\n}\n",[42,1108,1109,1127,1137,1145],{"__ignoreMap":77},[81,1110,1111,1114,1116,1119,1122,1125],{"class":83,"line":84},[81,1112,1113],{"class":87},"Page",[81,1115,489],{"class":91},[81,1117,1118],{"class":87},"T",[81,1120,1121],{"class":91},"> ",[81,1123,1124],{"class":101},"=",[81,1126,853],{"class":91},[81,1128,1129,1132,1134],{"class":83,"line":231},[81,1130,1131],{"class":91},"  items : [",[81,1133,1118],{"class":87},[81,1135,1136],{"class":91},"],\n",[81,1138,1139,1142],{"class":83,"line":238},[81,1140,1141],{"class":91},"  total : ",[81,1143,1144],{"class":87},"Integer\n",[81,1146,1147],{"class":83,"line":871},[81,1148,731],{"class":91},[11,1150,1151],{},"A generic is used by instantiating it:",[72,1153,1155],{"className":74,"code":1154,"language":76,"meta":77,"style":77},"Person = { name: String }\n\nPage\u003CPerson>\n",[42,1156,1157,1170,1174],{"__ignoreMap":77},[81,1158,1159,1162,1164,1166,1168],{"class":83,"line":84},[81,1160,1161],{"class":172},"Person",[81,1163,176],{"class":101},[81,1165,822],{"class":91},[81,1167,122],{"class":87},[81,1169,609],{"class":91},[81,1171,1172],{"class":83,"line":231},[81,1173,235],{"emptyLinePlaceholder":234},[81,1175,1176,1178,1180,1182],{"class":83,"line":238},[81,1177,1113],{"class":87},[81,1179,489],{"class":91},[81,1181,1161],{"class":87},[81,1183,789],{"class":91},[11,1185,1186],{},"A generic may take several parameters:",[72,1188,1190],{"className":74,"code":1189,"language":76,"meta":77,"style":77},"Resource\u003CT,A> = {\n  data  : T,\n  meta  : A,\n  links : [String]\n}\n",[42,1191,1192,1213,1223,1232,1241],{"__ignoreMap":77},[81,1193,1194,1197,1199,1201,1204,1207,1209,1211],{"class":83,"line":84},[81,1195,1196],{"class":87},"Resource",[81,1198,489],{"class":91},[81,1200,1118],{"class":87},[81,1202,1203],{"class":91},",",[81,1205,1206],{"class":87},"A",[81,1208,1121],{"class":91},[81,1210,1124],{"class":101},[81,1212,853],{"class":91},[81,1214,1215,1218,1220],{"class":83,"line":231},[81,1216,1217],{"class":91},"  data  : ",[81,1219,1118],{"class":87},[81,1221,1222],{"class":91},",\n",[81,1224,1225,1228,1230],{"class":83,"line":238},[81,1226,1227],{"class":91},"  meta  : ",[81,1229,1206],{"class":87},[81,1231,1222],{"class":91},[81,1233,1234,1237,1239],{"class":83,"line":871},[81,1235,1236],{"class":91},"  links : [",[81,1238,122],{"class":87},[81,1240,704],{"class":91},[81,1242,1243],{"class":83,"line":880},[81,1244,731],{"class":91},[11,1246,1247],{},"Instantiations are independent of one another: the same generic can be used\nseveral times in one schema, with different arguments each time.",[72,1249,1251],{"className":74,"code":1250,"language":76,"meta":77,"style":77},"{\n  people   : Page\u003CPerson>,\n  products : Page\u003CProduct>\n}\n",[42,1252,1253,1258,1272,1286],{"__ignoreMap":77},[81,1254,1255],{"class":83,"line":84},[81,1256,1257],{"class":91},"{\n",[81,1259,1260,1263,1265,1267,1269],{"class":83,"line":231},[81,1261,1262],{"class":91},"  people   : ",[81,1264,1113],{"class":87},[81,1266,489],{"class":91},[81,1268,1161],{"class":87},[81,1270,1271],{"class":91},">,\n",[81,1273,1274,1277,1279,1281,1284],{"class":83,"line":238},[81,1275,1276],{"class":91},"  products : ",[81,1278,1113],{"class":87},[81,1280,489],{"class":91},[81,1282,1283],{"class":87},"Product",[81,1285,789],{"class":91},[81,1287,1288],{"class":83,"line":871},[81,1289,731],{"class":91},[11,1291,1292],{},"Constraints declared on a generic apply to every instantiation:",[72,1294,1296],{"className":74,"code":1295,"language":76,"meta":77,"style":77},"Page\u003CT> = {\n  items : [T],\n  total : Integer\n}( p | consistent: p.items.length == p.total )\n",[42,1297,1298,1312,1320,1326],{"__ignoreMap":77},[81,1299,1300,1302,1304,1306,1308,1310],{"class":83,"line":84},[81,1301,1113],{"class":87},[81,1303,489],{"class":91},[81,1305,1118],{"class":87},[81,1307,1121],{"class":91},[81,1309,1124],{"class":101},[81,1311,853],{"class":91},[81,1313,1314,1316,1318],{"class":83,"line":231},[81,1315,1131],{"class":91},[81,1317,1118],{"class":87},[81,1319,1136],{"class":91},[81,1321,1322,1324],{"class":83,"line":238},[81,1323,1141],{"class":91},[81,1325,1144],{"class":87},[81,1327,1328,1331,1333,1335,1338,1341,1344],{"class":83,"line":871},[81,1329,1330],{"class":91},"}( ",[81,1332,11],{"class":271},[81,1334,275],{"class":101},[81,1336,1337],{"class":172}," consistent",[81,1339,1340],{"class":91},": p.items.length ",[81,1342,1343],{"class":101},"==",[81,1345,1346],{"class":91}," p.total )\n",[611,1348,1350,1357],{":unsupported":1349},"true",[11,1351,1352,1353,1356],{},"Instantiating a generic with another instantiation — ",[42,1354,1355],{},"Resource\u003CPage\u003CPerson>>","\n— does not parse in either implementation. Name the inner type first:",[72,1358,1360],{"className":74,"code":1359,"language":76,"meta":77,"style":77},"People = Page\u003CPerson>\nResource\u003CPeople>\n",[42,1361,1362,1378],{"__ignoreMap":77},[81,1363,1364,1367,1369,1372,1374,1376],{"class":83,"line":84},[81,1365,1366],{"class":172},"People",[81,1368,176],{"class":101},[81,1370,1371],{"class":87}," Page",[81,1373,489],{"class":91},[81,1375,1161],{"class":87},[81,1377,789],{"class":91},[81,1379,1380,1382,1384,1386],{"class":83,"line":231},[81,1381,1196],{"class":87},[81,1383,489],{"class":91},[81,1385,1366],{"class":87},[81,1387,789],{"class":91},[107,1389,1391],{"id":1390},"abstract-data-types","Abstract Data types",[11,1393,1394,1395,1398],{},"Abstract data types, also called user-defined types, provide the way to define\nhigher level abstractions easily and to optionally connect them to types of\nthe host language. For instance, a ",[42,1396,1397],{},"Color"," abstraction can be defined as\nfollows:",[72,1400,1402],{"className":74,"code":1401,"language":76,"meta":77,"style":77},"Color = \u003Crgb> {r: Byte, g: Byte, b: Byte},\n        \u003Chex> String( s | \u002F^#[0-9a-f]{6}$\u002Fi.test(s) )\n",[42,1403,1404,1434],{"__ignoreMap":77},[81,1405,1406,1408,1410,1412,1416,1419,1422,1425,1427,1429,1431],{"class":83,"line":84},[81,1407,1397],{"class":172},[81,1409,176],{"class":101},[81,1411,776],{"class":91},[81,1413,1415],{"class":1414},"s9eBZ","rgb",[81,1417,1418],{"class":91},"> {r: ",[81,1420,1421],{"class":87},"Byte",[81,1423,1424],{"class":91},", g: ",[81,1426,1421],{"class":87},[81,1428,473],{"class":91},[81,1430,1421],{"class":87},[81,1432,1433],{"class":91},"},\n",[81,1435,1436,1439,1442,1444,1446,1448,1450,1452,1455],{"class":83,"line":231},[81,1437,1438],{"class":91},"        \u003C",[81,1440,1441],{"class":1414},"hex",[81,1443,1121],{"class":91},[81,1445,122],{"class":87},[81,1447,268],{"class":91},[81,1449,412],{"class":271},[81,1451,275],{"class":101},[81,1453,1454],{"class":561}," \u002F^#[0-9a-f]{6}$\u002Fi",[81,1456,1457],{"class":91},".test(s) )\n",[11,1459,1460,1461,49,1463,1465,1466,1469],{},"The Color definition above shows that a color can be represented either by a\nRGB triple (through a tuple type), or by a hexadecimal string (e.g. #8a2be2).\n",[42,1462,1415],{},[42,1464,1441],{}," are called the ",[37,1467,1468],{},"information representations"," of the Color\nabstraction.",[11,1471,1472,1473,1477],{},"Connecting those representations to a class of the host language is what\n",[131,1474,1476],{"href":1475},"\u002Freference\u002F0.4.x\u002Finformation-contracts","information contracts"," are about.",[107,1479,1481],{"id":1480},"comments-and-metadata","Comments and metadata",[11,1483,1484,1487,1488,1491],{},[42,1485,1486],{},"#"," starts a line comment. ",[42,1489,1490],{},"\u002F- ... -\u002F"," delimits a block comment:",[72,1493,1495],{"className":74,"code":1494,"language":76,"meta":77,"style":77},"# a line comment\n\n\u002F- a block\n   comment -\u002F\nAge = Integer\n",[42,1496,1497,1502,1506,1511,1516],{"__ignoreMap":77},[81,1498,1499],{"class":83,"line":84},[81,1500,1501],{"class":203},"# a line comment\n",[81,1503,1504],{"class":83,"line":231},[81,1505,235],{"emptyLinePlaceholder":234},[81,1507,1508],{"class":83,"line":238},[81,1509,1510],{"class":91},"\u002F- a block\n",[81,1512,1513],{"class":83,"line":871},[81,1514,1515],{"class":91},"   comment -\u002F\n",[81,1517,1518,1521,1523],{"class":83,"line":880},[81,1519,1520],{"class":172},"Age",[81,1522,176],{"class":101},[81,1524,1525],{"class":87}," Integer\n",[11,1527,1528,1529,1532],{},"The block form doubles as metadata when it contains ",[42,1530,1531],{},"key: value"," pairs. The\nmetadata attaches to the definition that follows and is available for tooling\nsuch as documentation or JSON Schema generation:",[72,1534,1536],{"className":74,"code":1535,"language":76,"meta":77,"style":77},"\u002F- label: \"Age\", description: \"The age of a person, in years\" -\u002F\nAge = Integer( i | i >= 0 )\n",[42,1537,1538,1543],{"__ignoreMap":77},[81,1539,1540],{"class":83,"line":84},[81,1541,1542],{"class":561},"\u002F- label: \"Age\", description: \"The age of a person, in years\" -\u002F\n",[81,1544,1545,1547,1549,1551,1553,1555,1557,1559,1561,1563],{"class":83,"line":231},[81,1546,1520],{"class":172},[81,1548,176],{"class":101},[81,1550,265],{"class":87},[81,1552,268],{"class":91},[81,1554,272],{"class":271},[81,1556,275],{"class":101},[81,1558,278],{"class":91},[81,1560,281],{"class":101},[81,1562,284],{"class":87},[81,1564,287],{"class":91},[1566,1567,1568],"style",{},"html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":77,"searchDepth":238,"depth":238,"links":1570},[1571,1572,1573,1574,1578,1579,1580,1581,1582,1585,1586,1587,1588],{"id":109,"depth":231,"text":110},{"id":158,"depth":231,"text":159},{"id":182,"depth":231,"text":183},{"id":246,"depth":231,"text":247,"children":1575},[1576,1577],{"id":387,"depth":238,"text":388},{"id":532,"depth":238,"text":533},{"id":626,"depth":231,"text":627},{"id":680,"depth":231,"text":681},{"id":707,"depth":231,"text":708},{"id":757,"depth":231,"text":758},{"id":792,"depth":231,"text":793,"children":1583},[1584],{"id":915,"depth":238,"text":916},{"id":1005,"depth":231,"text":1006},{"id":1099,"depth":231,"text":1100},{"id":1390,"depth":231,"text":1391},{"id":1480,"depth":231,"text":1481},"Finitio 0.4 type system: how information types are built.","md",{},"\u002Freference\u002F0.4.x\u002Ftype-system",{"title":5,"description":1589},"reference\u002F0.4.x\u002Ftype-system","0.4.x","fO3HT3ksLGoVeySlqg6JJbzN1AvDrqlmlnTdJ2QlM9I",[1598,1601],{"path":1599,"title":1600},"\u002Fuse-cases","Use cases",{"path":1602,"title":1603},"\u002Fuse-cases\u002Fcleaning-csv-files","Cleaning .csv files",1786026251330]