NAME Type::Tie::Aggregate - like Type::Tie, but slower and more flexible VERSION version 0.001 SYNOPSIS use Type::Tie::Aggregate; use Types::Standard qw(Dict Optional Num Str); ttie my %hash, Dict[name => Str, age => Optional[Num]], ( name => 'John Doe', age => 42, ); $hash{name} = 'Jane Doe'; # ok $hash{age}++; # ok $hash{age} = 'forty-two; # dies delete $hash{name}; # dies ('name' is mandatory) # Unfortunately this does not work, because the hash is # momentarily cleared and will no longer pass the type constraint # (which requires a 'name' key). %hash = (name => 'J. Random Hacker'); # Use this instead (also more efficient). (tied %hash)->initialize(name => 'J. Random Hacker'); DESCRIPTION Like Type::Tie, this module exports a single function: ttie. Also like Type::Tie, ttie ties a variable to a type constraint (coercions will be honored). However, unlike Type::Tie, when an assignment happens on a variable tied with ttie, the entire variable will be re-checked, not just the value that was added. This is much more expensive, of course, but can be very useful for structured types such as Dict from Types::Standard as show in the "SYNOPSIS". Any type constraints supporting the Type::API interface should work, not just Type::Tiny types. However, in the examples that follow, all type constraints are from Types::Standard unless specified otherwise. Initialization and Re-initialization Since some types don't allow empty values (see the "SYNOPSIS"), values may need to be given when initializing the type. For example, this is invalid: ttie my %hash, Dict[name => Str]; # dies No values were given to initialize %hash, so %hash failed the type constraint Dict[name = Str]> (which requires a name key). Instead, this should be done: ttie my %hash, Dict[name => Str], (name => 'My Name'); This initializes %hash with the value (name => 'My Name') before any type checking is performed, so, at the end of the day, %hash passes the type constraint. Another important thing to note is that when a variable is re-initialized, it is temporarily emptied. So the following is invalid: ttie my %hash, Dict[name => Str], (name => 'My Name'); %hash = (name => 'Other Name'); # dies Instead, the initialize method should be used on the tied object, like so: ttie my %hash, Dict[name => Str], (name => 'My Name'); (tied %hash)->initialize(name => 'Other Name'); # ok This is also more efficient than the previous method. Deep Tying ttie ties variables deeply, meaning that if any references contained within the variable are changed, the entire variable is rechecked against the type constraint. Blessed objects are not deeply tied, but tied references are and the functionality of these tied references is preserved. For example, the following Does The Right Thing(TM): ttie my %hash, HashRef[ArrayRef[Int]]; $hash{foo} = [1, 2, 3]; # ok $hash{foo}[0] = 'one'; # dies $hash{bar} = [3, 2, 1]; # ok push @{$hash{bar}}, 'zero'; # dies This also works: use List::Util qw(all); use Tie::RefHash; ttie my @array, ArrayRef[HashRef[Int]]; my $scalar_key = 'scalar'; my @array_key = (1, 2, 3); tie my %refhash, 'Tie::RefHash', ( \$scalar_key => 1, \@array_key => 2, ); push @array, \%refhash; $array[0]{\$scalar_key} = 'foo'; # dies $array[0]{\@array_key} = 42; # ok all { ref ne '' } keys %{$array[0]}; # true Currently, circular references are not handled correctly (see "Circular References"). FUNCTIONS ttie ttie my $scalar, TYPE, $init_val; ttie my @array, TYPE, @init_val; ttie my %hash, TYPE, %init_val; Tie $scalar, @array, or %hash to TYPE and initialize with $init_val, @init_val, or %init_val. METHODS initialize (tied $scalar)->initialize($init_val); (tied @array)->initialize(@init_val); (tied %hash)->initialize(%init_val); Re-initialize $scalar, @array, or %hash. This is necessary because some types don't allow an empty value, and the variable will temporarily be emptied (except for scalars) if initialized the usual way (e.g., @array = qw(foo bar baz)). This is also more efficient than conventional initialization. See "Initialization and Re-initialization" for more info. type my $type = (tied VAR)->type; Return the type constraint for VAR. Note that the type cannot currently be set, only read. CAVEATS Re-initialization Re-initialization of tied variables using @array = @init or %hash = %init does not always work. Use (tied @array)->initialize(@init) and (tied %hash)->initialize(%init) instead. See "Initialization and Re-initialization" for more information. Retying References If a variable tied to a type contains a reference, then that reference cannot be contained by any other variable tied to a type. For example, the following will die: my $arrayref = [42]; ttie my @num_array, ArrayRef[ArrayRef[Num]], ($arrayref); ttie my @str_array, ArrayRef[ArrayRef[Str]], ($arrayref); If this were allowed, it would not be clear whether push @$arrayref, 'foo' should die or not. This behavior may be changed in a later release, but you probably should not be doing this regardless. Circular References Circular references are not handled correctly. Hopefully this will be fixed in a future release. BUGS Please report any bugs or feature requests on the bugtracker website https://rt.cpan.org/Public/Dist/Display.html?Name=Type-Tie-Aggregate or by email to bug-Type-Tie-Aggregate@rt.cpan.org . When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. SEE ALSO * Type::Tie AUTHOR Asher Gordon COPYRIGHT AND LICENSE Copyright (C) 2021 Asher Gordon This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .