# perldoc > Variable::Magic

---
type: CommandReference
command: Variable::Magic
mode: perldoc
section: ""
source: perldoc
---

## Quick Reference

- `use Variable::Magic qw<wizard cast VMG_OP_INFO_NAME>` — import functions and constants
- `wizard(%args)` — create a magic wizard object
- `cast $var, $wiz, @args` — attach wizard magic to a variable
- `getdata $var, $wiz` — fetch private data attached to a variable by a wizard
- `dispell $var, $wiz` — remove wizard magic from a variable
- `cast $x, $wiz, 1` — cast with data constructor argument
- `cast $ENV{TZ}, wizard set => sub { POSIX::tzset(); () }` — trigger action on variable change

## Name

Variable::Magic - Associate user-defined magic to variables from Perl.

## Synopsis

perl
use Variable::Magic qw<wizard cast VMG_OP_INFO_NAME>;

# A variable tracer
my $wiz = wizard(
  set  => sub { print "now set to ${$_[0]}!\n" },
  free => sub { print "destroyed!\n" },
);
my $a = 1;
cast $a, $wiz;
$a = 2;        # prints "now set to 2!"
# prints "destroyed!" when $a goes out of scope

# A hash with a default value
my $wiz = wizard(
  data     => sub { $_[1] },
  fetch    => sub { $_[2] = $_[1] unless exists $_[0]->{$_[2]}; () },
  store    => sub { print "key $_[2] stored in $_[-1]\n" },
  copy_key => 1,
  op_info  => VMG_OP_INFO_NAME,
);
my %h = (_default => 0, apple => 2);
cast %h, $wiz, '_default';
print $h{banana}, "\n"; # prints "0"
$h{pear} = 1;           # prints "key pear stored in helem"
## Functions

### `wizard(%args)`

Creates a wizard object. Keys:

- `data` — code reference to private data constructor; called with `($_[0] => ref to var, @_[1..@_-1] => extra cast args)`
- `get`, `set`, `len`, `clear`, `free`, `copy`, `local`, `fetch`, `store`, `exists`, `delete` — code (or string) references to magic callbacks. Callback signature: `($ref, $data [, $key, $elt [, $op]])` depending on type. `len` expects return of new length. For `copy_key => 1`, `$_[2]` is a copy allowing safe assignment.
- `op_info` — `0`, `VMG_OP_INFO_NAME`, or `VMG_OP_INFO_OBJECT`; appends extra element to `@_`: op name or `B::OP` object.

Each callback can be a code ref, a string ref (sub name), or a reference to `undef` (no-op).

### `cast [$@%&*]var, $wiz, @args`

Attaches `$wiz` magic to variable. Returns true on success or if already attached, croaks on error. Data constructor called with `($_[0] => ref to var, @args)`.

### `getdata [$@%&*]var, $wiz`

Returns private data associated with `$wiz` in variable. Croaks if `$wiz` invalid, returns empty list if no magic or no data constructor.

### `dispell [$@%&*]variable, $wiz`

Dissociates `$wiz` magic from variable. Returns true on success, 0 if no such magic, croaks if wizard invalid.

## Constants

- `MGf_COPY` — true if *copy* magic available (perl 5.7.3+)
- `MGf_DUP` — true if *dup* magic available (perl 5.7.3+)
- `MGf_LOCAL` — true if *local* magic available (perl 5.9.3+)
- `VMG_UVAR` — true if *fetch*, *store*, *exists*, *delete* magics on hashes available (perl 5.9.5/5.10.0+)
- `VMG_COMPAT_SCALAR_LENGTH_NOLEN` — true if *len* magic not called for `length` on scalars
- `VMG_COMPAT_SCALAR_NOLEN` — true if *len* magic not called on scalars at all
- `VMG_COMPAT_ARRAY_PUSH_NOLEN` — true if *len* magic not called on push in non-void context (perl 5.11.0+)
- `VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID` — true if *len* magic not called on push in void context
- `VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID` — true if *len* magic not called on unshift in void context
- `VMG_COMPAT_ARRAY_UNDEF_CLEAR` — true if *clear* magic called when undefining arrays
- `VMG_COMPAT_HASH_DELETE_NOUVAR_VOID` — true if *delete* magic not called on hash delete in void context
- `VMG_COMPAT_CODE_COPY_CLONE` — true if *copy* magic called when cloning closure prototypes (perl 5.17.0+)
- `VMG_COMPAT_GLOB_GET` — true if *get* magic called for glob operations
- `VMG_PERL_PATCHLEVEL` — perl patchlevel this module was built with, or 0
- `VMG_THREADSAFE` — true if built with thread-safety
- `VMG_FORKSAFE` — true if built with fork-safety (always true except Windows perl 5.10.0-)
- `VMG_OP_INFO_NAME` — value for `op_info` to get current op name
- `VMG_OP_INFO_OBJECT` — value for `op_info` to get `B::OP` object

## Examples

### Associate an object to any perl variable

perl
package Magical::UserData;
use Variable::Magic qw<wizard cast getdata>;
my $wiz = wizard data => sub { \$_[1] };
sub ud (\[$@%&*]) : lvalue {
  my ($var) = @_;
  my $data = &getdata($var, $wiz);
  unless (defined $data) {
    $data = \(my $slot);
    &cast($var, $wiz, $slot) or die "Couldn't cast UserData magic";
  }
  $$data;
}
package main;
BEGIN { *ud = \&Magical::UserData::ud }
my $cb;
$cb = sub { print 'Hello, ', ud(&$cb), "!\n" };
ud(&$cb) = 'world';
$cb->(); # Hello, world!
### Recursively cast magic on datastructures

perl
my $wiz;
$wiz = wizard data => sub {
   my ($var, $depth) = @_;
   $depth ||= 0;
   my $r = ref $var;
   if ($r eq 'ARRAY') {
     &cast((ref() ? $_ : \$_), $wiz, $depth + 1) for @$var;
   } elsif ($r eq 'HASH') {
     &cast((ref() ? $_ : \$_), $wiz, $depth + 1) for values %$var;
   }
   return $depth;
 },
 free => sub {
   my ($var, $depth) = @_;
   my $r = ref $var;
   print "free $r at depth $depth\n";
   ();
 };
 {
   my %h = ( a => [ 1, 2 ], b => { c => 3 } );
   cast %h, $wiz;
 } # prints free messages
### Delayed magic actions

perl
my $delayed;
my $delayed_aux = wizard(
  data => sub { $_[1] },
  free => sub {
    my ($target) = $_[1];
    my $target_data = &getdata($target, $delayed);
    local $target_data->{guard} = 1;
    if (ref $target eq 'SCALAR') {
      my $orig = $$target;
      $$target = $target_data->{mangler}->($orig);
    }
    return;
  },
);
$delayed = wizard(
  data => sub { return +{ guard => 0, mangler => $_[1] }; },
  set  => sub {
    return if $_[1]->{guard};
    my $token;
    cast $token, $delayed_aux, $_[0];
    return \$token;
  },
);
my $x = 1;
cast $x, $delayed => sub { $_[0] * 2 };
$x = 2;
# $x is now 4
my @y = ($x = 5, $x);
# $x is now 10, @y is (5, 5)
## See Also

- [perlguts](perldoc://perlguts) and [perlapi](perldoc://perlapi) for internal magic information
- [perltie](perldoc://perltie) and [overload](perldoc://overload) for other ways of enhancing objects