3 Specification - Technical details for dependent types
7 Specification for extra, declaritive hinting to type constrain definitions.
11 We'd like to be able to add additional 'facets' when declaring our type
12 constraints. These hints would form an extention to the core types built into
13 Moose, such as Str, Object, etc. as well as form the foundation for authors of
14 Type Constraint extentions to also add these hints. The idea is these hints
15 would allow us to move a lot of the more common constraint types from the
16 where clause of a subtype to the subtype meta data. This would make it simple
17 to create a lot of the more common constraint types, improving usability and
18 consistency. Also, since the implementations for these constraints would be
19 universally vetted, we are likely to improve global code quality.
21 Additional advantages would be those derived from the common code ecosystem,
22 that is that more people would share common knowledge, improving our ability
23 to build a strong community of shared best practices.
25 Lastly, by hinting type constraints with additional metadata, the possibility
26 to introspect that metadata usefully for code generation becomes possible. In
27 particular, we'd like these additional constraints to fit neatly with existing
28 code generation and mapping tools, such asd DBIx-Class, Reaction, Ernst, etc.
30 So, an important goal of choosing the hints to to choose and define ones that
31 can be mapped to other type constraint systems. For example, having a maximum
32 length hint for a string type would map well to most database column types,
33 but a hint to match a string to a regular expression should be defined
34 carefully, since most databases have limited if any abilities to do this.
36 Therefore, it will be important to make sure the hinting system can degrade or
37 cast gracefully, that way hints defined at the application level will work
38 neatly with those defined at a possible database level.
40 =head1 PROPOSED SYNTAX
42 The following is proposed syntax for the faceted types:
46 which hasMinLenth(5), hasMaxLength(20),
51 The following are possible use cases.
55 It's common to add additional constraints to the STR type. How many times have
56 you done something like:
58 my $tc = subtype MaxStr10, as Str, where { length($_) <= 10 };
60 To create a string of 10 characters or less. Since this constraint is captured
61 in the code block it is not introspecable. A possible syntax to declare a Str
62 type constraint with a maximum length hint might be:
64 my $tc = subtype MaxStr10, as Str, which hasMaxInclusiveLength(10);
66 this information might be introspectable via something like:
68 $tc->meta->facets->max_length_inclusive; ## returns 10
70 =head2 DataTime and coercion possibilities
72 The following example shows how this system could work to enhance type
73 constraints in the MooseX-Types* namespace. It also shows how coercions could
74 be hooked into the hint system to allow more finely tuned coercions:
76 use MooseX::Types::DateTime qw(DateTime);
78 subtype USEasternDataTime,
80 which hasTimeZone('US/Eastern');
82 coerce USEasternDataTime,
84 which hasTimeZone('Floating')
85 via {$_->timezone('US/Eastern')};
87 The created subtype USEasternDataTime would only pass if the DateTime object
88 has the defined timezone. Their is a coercion that would adjust timezone
89 information to the canonical type.
91 =head2 Code generation and mapping
93 Given a type constraint such as:
97 which hasMaxInclusiveLength(45), isAlpha(),
99 That becomes part of a class definition:
101 package MyApp::Person;
103 has 'name' => (isa=>ValidName, required=>1);
105 A code generator or interpreter could introspect the metadata on the attribute
106 'short_name' to create a table like:
108 CREATE TABLE Person (
109 short_name varchar(45)
112 Please note how the code generator would need to aggregate meta information from
113 both the attribute options as well as it's type constraint, since in this case
114 the attribute is required. Here's another, more complicated option.
116 package MyApp::Types::StatisticsPeople;
118 ## both types are limited to 45 alphabetical characters that define a
119 ## single word (no whitespace before or after), like "John", but not allow
120 ## " John", " John ", "john123", etc.
124 which hasMaxInclusiveLength(45), isAlpha(), isWord();
128 which hasMaxInclusiveLength(45), isAlpha(), isWord();
130 package MyApp::Person;
133 use MyApp::Types::StatisticsPeople (qw/FirstName LastName/);
135 has first_name => (isa=>FirstName, required=>1);
136 has last_name => (isa=>LastName, required=>1);
138 The above might be generated into sql like so (let's assume a database that
139 has schema support, like Postgresql,
141 CREATE TABLE StatisticsPeople.FirstName (
144 PRIMARY KEY('first_name_id')
147 CREATE TABLE StatisticsPeople.LastName (
150 PRIMARY KEY('last_name_id')
153 CREATE TABLE PersonFirstName (
155 fk_first_name_id uuid,
156 PRIMARY KEY('fk_person_id', 'fk_first_name_id'),
159 CREATE TABLE Person (
161 fk_first_name_id uuid,
162 fk_last_name_id uuid,
163 PRIMARY KEY ('person_id')
164 CONSTRAINT 'person_validname'
165 FOREIGN KEY ('fk_last_name_id')
166 REFERENCES 'ValidName' ('valid_name_id'),
169 my $person = model('Person')->create({
170 person_first_name => { first_name => {value=>'John'} },
174 Probably an extreme options, but if we have types with all this meta data, why
175 not have it reflect down to the database model?
177 [Addional Code examples to follow]
179 =head1 CORE TYPES AND FACET HEIRARCHY
181 The following is an outline of the possible hints associated with core Moose
182 type constraints. Hints are assumed to be inherited.
195 LessThanOrEqual || '<='
197 GreaterThanOrEqual || '>='
217 isDigits* (That is, a string that is a number like "123")
218 Word (must be a single 'word')
224 * Might be better as a general encoding type.
227 PackageBase (For stuff like '::Plugin::MyPlugin')
254 Might like to have some stuff from the Math packages, like to validate if a
255 value matches a given function, or is in the domain or range of a function.