'Needless flexibilities' and structured records [very long]

Discussion in 'Perl Misc' started by Rainer Weikusat, Mar 15, 2013.

  1. NB: This is a lenghty multi-section texts starting with an explanation
    of 'the basics' for anybody who might have been so unfortunate to
    encounter Perl at version 5.16 or later. There's something which isn't
    an explanation at the end. Any kind of constructive criticism is
    welcome.

    NB^2: I wrote this because I wanted to write it for some time. In line
    with 'the base of any sound order is a large wastepaper bin' (Kurt
    Tucholsky), "Stop shaking your dick in public, people are staring
    already" and similar cheesinesses are just a short way into my
    scorefile, alongside the large set of 'less than instructive posters'
    who reside there already.


    1. Objects, References and Methods
    ----------------------------------

    One of the more unique features of Perl OO is that there is no such
    thing as a unique, language-enforced representation for 'object
    instances'. Perl has a number different kinds of builtin objects, the
    most prominent ones would be scalars, arrays and hashes. glob objects
    are used to store symbol table entries and also, to access file and
    directory handles. code objects represent subroutines. There's also a
    probably lesser-known one, namely, the lvalue object. Presumably (I
    didn't test this) it is used as actual 'return value' of an lvalue
    subroutine and it can also be 'caught in flight' when using certain
    built-in subroutines/ operators, eg

    perl -e '$w = "Hello"; $lv = \substr($w, 1, 3); print $lv, "\n"; $$lv = "aird"; print $w, "\n"'

    will print

    LVALUE(0x620d70)
    Hairdo

    References to objects of all these kinds can be created by applying
    the backslash operator to an object of a certain kind or by using a
    special 'anonymous object' construction syntax, eg

    \%hash

    return a reference to the hash %hash and

    [1,2,3]

    returns a reference to an anonymous array containing the values 1, 2
    and 3.

    Any reference can be associated with a package with the help of the
    bless function. When a reference is associated with a package, the
    syntax

    $ref->name(argument, ...)

    can be used to request a 'method call': This will search for a
    subroutine named name in the package $ref is currently associated with
    and in all packages this package declared as its parent
    packages. Because this 'subroutine search' happens at runtime using
    the string 'name' as key, this is really rather a message-passing
    mechanism than something like the 'virtual methods' provided by C++.

    The implication of this is that any Perl object can acquire OO-like
    features via attaching a reference to the object to a package while
    otherwise retaining its built-in behaviour.


    Example: File Handle Objects
    ----------------------------

    A relatively simple uncommon example: In a certain program, I'm using
    Linux 'queued realtime signals' for I/O event notification. This
    requires manipulating the file status flags associated with the
    corresponding file descriptor (via fcntl) to set the owner of the file
    and the signal which is supposed to be sent in case of an 'I/O
    readiness' event for this file descriptor to to set or clear the
    O_ASYNC flag when such signals should or shouldn't be sent. fcntl is
    an all-or-nothing operation which changes all flags of a file
    descriptor. In order to modify individual flags selectively, the
    corresponding bits need to be set or cleared in an integer
    representing the set of all flags bits. Since file handles are
    nowadays usually references to anonymous globs, they can be blessed
    into a package in order to support calling methods on them. In this
    case, this would be an enable_async method which enables asynchronous
    notifcations and a disable_async method. The current flag set is
    stored in the scalar slot of the glob. Because the glob is stilla
    glob, it can otherwise be used just like any other file handle.

    ,----
    | This is what the Perl 6 OO design document refers to as 'It is too
    | minimal': It supports too many features many people never use because
    | they have no idea what they'd be good for (because
    | $better_known_oo_language didn't provide them)
    `----


    2. And Records?
    ---------------

    Unfortunately, something Perl doesn't provide is a complex datatype
    whose components can be accessed by name instead of using an integer
    (array) or string (hash) key. Such record or structure types (or
    constructs conceptually derived from them) are usually used as object
    representation in other languages, not the least because they nest
    properly.

    Example in C
    ------------

    Assuming the type definitions

    struct person {
    char *forename, *surname;
    };

    and

    struct citizen {
    struct person person;
    char *nationality;
    }

    and the variable definitions

    struct citizen someone = { .person = { .forename = 'Zarathustra' }'};
    struct person *person;

    the person pointer can point to a struct citizen,

    person = (struct person *)&someone;

    and can be used to access the 'struct person' fields,

    puts(person->forname);

    This obviously lends itself to implementing 'data inheritance' in
    addition to 'method inheritance.


    Hashes perhaps?
    ---------------

    An obvious idea ('the obvious idea') to provide a similar facility in
    Perl are hashes because these are 'dictionary' (or 'associative array')
    data structures mapping string keys to abitrary 'other' (scalar)
    values.

    ,----
    | At this point in the story, the PHP (or Java) programmer
    | probably leans back with a sigh of relief because 'the solution' just
    | presented itself and thus, there's no further requirement to think
    | about all this complicated stuff just in order to "get shit done
    | quickly" aka 'web development' (the 'get ...' is a quote from an
    | article about 'web frameworks' I read a while ago).
    `----

    But often, hashes/ references to anonymous hashes are not really a
    good choice for representing objects because 'a hash' is essentially
    an allocation scheme for array slots suposed to map all members of a
    'large' (or numerically discontinuous) set of 'keys' to such array
    slots by running a (seriously) lossy compression function on the key
    in order to transform it into a slot number based on the assumption
    that the actual number of different keys in the hash will always be
    much smaller than the number of elements in the key set and combining
    that with a mechansism to deal with so-called 'hash collision', cases
    where the result of the lossy compression function is identical for
    two keys which are actually different. *If* the number of actual
    collisions in the hash table is small, key insert, delete and lookup
    operations performed on it will complete in constant time, although
    they are still fairly expensive because of the compression
    function. In order to ensure that the number of collisions will be
    small, hash tables are usually (and possibly significantly) larger
    than what would be required if the keys could just be packed into
    successive slots of the table.

    Another problem with using hashes as object representation is that the
    'namespace' of each individual hash is 'global': If two related
    packages use the same name for an object property, they will end up
    using the same 'virtual property slot' and there's no easy way for
    preventing that.

    A possible way would be to prefix the package name to each property
    name and hope that all other packages also do this. But since package
    names are often longish, this is an unwiedly workaround. A workaround
    for the workaround would be to use declared constants whose values are
    the long property names and whose names are short enough to be used
    comfortably. But - alas - the {} autoquotes the key if it 'looks like
    a string' and this means that

    use constant NAME => __PACKAGE__.'name';

    $h->{NAME} = 'Paul';

    doesn't work. A workaround for the workaround for the workaround would
    be to invoke the 'constant subroutine' explicitly,

    $h->{NAME()} = 'Paul';

    but the two added noise characters are rather ugly.

    Lastly, the hash lookup which is a rather costly operation happens
    every time such a named property is accessed.


    A Better Idea: Arrays
    ---------------------

    Accessing slots of an array is a cheap O(1) operation and arrays don't
    need to be larger than necessary to accommodate the number of elements
    stored in them in order to workaround the fact that slots are
    allocated based on the result of a (seriously) lossy compression
    function applied to the key. Since the Perl OO system is 'too minimal'
    aka 'provides to many weird features', array references can also
    serve as 'invocant objects' for method calls.

    Two remaining problems are

    1. Obviously, accessing instance properties by index number is not a
    good idea except in very trivial cases.

    2. Slot allocation for related classes.

    (1) can be solved by declaring named constants with integer values and
    using these in the source code. The nice properties of this are that
    names declared in different packages don't collide, that the
    translation into slot number happens at compile time and that the []
    require no synactical workarounds for this case.

    use constant NAME => 0;

    $h->[NAME] = 'Emil';

    works as intended.

    It is possible to solve (2) by manageing slot numbers manually and
    such a scheme can be made to work for single-inheritance class
    hierarchies by using a 'magical name' to refer to the last slot number
    used by a certain package. Slot numbers for 'derived class' can then
    be calculated relative to the 'last used slot' number of the
    superclass. But this is still fairly inconvenient and the

    use constant PORP_A => 0;
    use constant PORP_B => 1;
    use constant PORP_C => 2;

    requires a lot of typing.


    Automatic Compile-Time Allocation of Array Slots
    ------------------------------------------------

    The

    use something (...)

    feature can be used to execute a subroutine named something::import at
    compile time. By combining this with the existing constant module and
    some fairly simple state-tracking code, it is possible to create slot
    name constants based on a use statement in a way which works for
    single-inheritance class hierachies:

    ---------------
    package slots;

    use feature 'state';
    use constant;

    sub import
    {
    state %counters;
    my ($ctr, $fields);

    if (ref($_[1])) {
    $fields = $_[1];
    $ctr = 0;
    } else {
    $ctr = $counters{$_[1]};
    $fields = $_[2];
    }

    @_ = ($_[0], {map { $_, $ctr++; } @$fields});

    $counters{caller()} = $ctr;

    goto &constant::import;
    }

    1;
    ---------------

    Assuming this code exists as slots.pm somewhere where perl can find
    it, a non-derived class could declare a set of 'slot names' by doing

    use slots [qw(FORENAME SURENAME)];

    and a class derived from this class could do

    use slots ('Person', ['NATIONALITY']);

    ('Person' being the name of the superclass package) to request an
    additional field which will have the next 'free' slot number.

    NB: This is an idea I had yesterday and since the implementation was
    so exceedingly simple, I thought sharing it might be a good idea. I
    expect that there situations this simple code doesn't handle but it is
    'good enough' to be useful.
    Rainer Weikusat, Mar 15, 2013
    #1
    1. Advertising

  2. Ben Morrow <> writes:

    [...]

    >> ---------------
    >> package slots;
    >>
    >> use feature 'state';
    >> use constant;
    >>
    >> sub import
    >> {
    >> state %counters;
    >> my ($ctr, $fields);
    >>
    >> if (ref($_[1])) {
    >> $fields = $_[1];
    >> $ctr = 0;
    >> } else {
    >> $ctr = $counters{$_[1]};

    >
    > You can look up the inheritance here instead of having the user specify
    > it (DRY and all that...). As long as they


    Re: DRY

    That's a cute acronym for 'Design pattern aficionados Reinventing
    elementary database theorY' (in short: Databases should not contain
    redundant copies of the same data to avoid so-called 'update
    anomalies', the database becoming inconsistent because not all
    redudant copies of 'some data' are changed during an update. People
    usually ignore that in favor of 'nobdoy will ever update X without
    going to gatekeeper code Z which always keeps all copies in sync' and
    looking dedicatedly in another direction whenever somebody mentions
    that 'updates withoug going throug Z' are possible. This could almost
    be called 'a basic design principle of modern Linux distributions'
    :->).

    >
    > use parent "Parent";
    > use slots qw/one two three/;
    >
    > in that order, @{ caller . "::ISA" } will contain the direct parents at
    > this point. You can also croak if they're trying to use MI.


    I thought about that and decided against it: This would require @ISA
    to be populated by the time the import method is executed and the code
    would either need to operate in 'pushy nanny mode' ("I've told you you
    must not inherit methods from more than one class and you must do as I say
    because I say so!") or make a guess at which of the possibly many
    direct and indirect(!) 'superclasses' is supposed to be the anchoring
    point for the new slot name series. But in reality, @ISA is about
    method lookups and not about 'allocating array slots in a
    non-conflicting way to members of some "inheritance tree"'.

    One can assume that packages sharing an array reference for instance
    data will usually also share method via @ISA but this need not be
    true. Also just because some package is listed in @ISA doesn't
    necessarily mean that it should also participiate in the 'data
    inheritance hierarchy'. These are orthogonal issues and one of the
    serious drawbacks of many existing 'OO support modules' is that the
    authors usually fell prey to their own "Jack of all trades" desires
    and 'hard-coded' technically independent policy choices they usually
    happen to make in their code. Eg, one cannot comfortably use parent.pm
    except if one always keeps each package in a file of its own, to name
    a simple example.

    'Radio and television' are popular because 'they just work': Turn them
    on, something's gonna happen, no need to worry about that. For the
    same reason, complaining about the programme is also very popular.

    >> $fields = $_[2];
    >> }
    >>
    >> @_ = ($_[0], {map { $_, $ctr++; } @$fields});

    >
    > Strictly this should be "constant" rather than $_[0] (which will be
    > "slots"), since this is supposed to be emulating constant->import. In
    > fact constant.pm doesn't care, but in principle it might care at some
    > point in the future.


    It would be 'constant' if constant::import had actually been
    invoked directly. But since this isn't the case and no 'requirements
    specification' of any kind exists (as far as I'm aware of that)
    anything would do insofar it pushes the first 'actual argument' to
    $_[1]. Using whatever was passed in $_[0] to this import routine is as
    good an anything as anything else and might also be useful 'in
    future'.

    >> $counters{caller()} = $ctr;
    >>
    >> goto &constant::import;

    >
    > It's probably easier to just create the constants manually, rather than
    > bothering with goto-&:
    >
    > for (@$fields) {
    > my $n = $ctr++;
    > no strict "refs";
    > *{ caller . "::$_" } = sub () { $n };
    > }
    >
    > If you were feeling excited you could use the scalar-refs-in-the-stash
    > trick constant.pm uses to avoid a full GV+CV.


    Ehh ... I'm using the 'scalar-refs-in-the-stash' trick and - for that
    matter - any useful other 'trick' constant.pm might employ now or in
    future. That's why I'm just telling constant.pm which constants I'd
    like to have created[*].

    This is also a design question: Since a subroutine providing the
    feature I want to build on already exists and the implementation is
    suitable for the task at hand, the code should rather invoke the
    subroutine than be decorated by copy of some of its code (this is also
    a 'DRY/ redundant copies of identical data' issue).

    [*] I've been using Perl 5 for long enough that I was pleasantly
    surprised when I could stop creating long

    sub A_VALUE() { 1; }
    sub ANOTHER() { 2; }

    ..
    ..
    ..

    cascades ...

    [...]

    >> use slots ('Person', ['NATIONALITY']);
    >>
    >> ('Person' being the name of the superclass package) to request an
    >> additional field which will have the next 'free' slot number.
    >>
    >> NB: This is an idea I had yesterday and since the implementation was
    >> so exceedingly simple, I thought sharing it might be a good idea. I
    >> expect that there situations this simple code doesn't handle but it is
    >> 'good enough' to be useful.

    >
    > It's not a bad idea; it's basically the same as Class::Accessor::Faster
    > or MooseX::ArrayRef.


    I assume the authors of the two named modules would calls this 'a
    backhanded compliment' (and rightly so :->) and so would I (also
    rightly so :->). This is a slight generalization of an anonymous array
    sharing scheme I've been using since 199x and it really doesn't (and
    shouldn't) do anything except solve this particular problem.

    > As you note, it only works for single inheritance,
    > and doesn't work with MI or roles-which-provide-attributes (however they
    > may be implemented); it also fails (badly) if you attempt to modify the
    > inheritance or attributes of a class at runtime.


    It can't 'fail badly at run-time' because the code never runs 'at
    run-time'. This 'anonymous array sharing scheme' might not be useful
    to solve 'certain problems' or might only be a component which could
    be employed for solving them. But that's a different conversation (I
    already wrote about the
    washer-dryer-lawnmower-bicycle-tophat-eggwarmer-hovercraft-theodolite
    .... sometimes, a hammer is really the right tool).

    > MI can be fixed by using accessor methods, since this allows a
    > subclass's implementation of ->foo to use a different slot from the
    > superclass's;


    A more general remark: At one end of the 'OO spectrum', you have
    something like CLOS or DYLAN (or Perl 6 or 'Perl With Mossy Antlers' or
    ....). These systems are based on an abstract, 'behavioural'
    specification of what 'an object instance' actually is. Nobody except
    the people who implemented the system knows that and its users can
    only interact with object instances by using a procedural
    interface. The obvious advantages of that would be that the object
    representation the system uses can change, either in future version or
    even at run-time, without affecting exising code.

    Then, there are intermediate/ hybrid systems like C++ or Java (or C)
    where the object representation was set in stone when the system was
    created but 'application code' does have direct access to object
    instances. This will usually be better for performance (although users
    of CLOS-style system will usually believe/ claim that 'the compiler'
    can 'optimize' this which may even be true .. but why use a lot of
    seriously complicated 'compiler technology' to make educated guesses
    at facts language users could easily have provided [and provided
    correctly] instead?).

    Lastly, on the opposite end of the spectrum, there's Perl 5 where users
    are in total control of object representation because the system only
    provides a (possibly hierarchivally structured) system for routing
    'messages' to 'message processing routines' (I propose a new 'flashy
    acronym' here, namely P5INAE --- for 'Perl 5 Is Not An Error'). The
    benefit is that what exactly constitues an object can be tailored to
    the problem at hand and the obvious drawback is that people actually
    have to do that.

    So far (evil anecdotical argument), I haven't been stopped by a brick
    wall when using that for the problems I head to deal
    with. Consequently, I'm not convinced that it needs to be replaced
    with a system based on different policy choices, especially
    considering that 'simple system for solving relatively simple
    problems' are useful because many problems are relatively simple
    (Corollary: Problems which only manifest themselves dreadfully in 'really
    large systems' could be a sign that createing 'really large systems'
    is 'a really bad idea').

    I'm also a firm desbeliever in 'the run-time environment has to defend
    itself agains one million evil typing monkeys'. That's a social
    problem and the solutions are 'education' and 'natural selection'.
    Rainer Weikusat, Mar 18, 2013
    #2
    1. Advertising

  3. Ben Morrow <> writes:
    > Quoth Rainer Weikusat <>:
    >> Ben Morrow <> writes:


    [...]

    >> > You can look up the inheritance here instead of having the user specify
    >> > it (DRY and all that...). As long as they

    >>
    >> Re: DRY
    >>
    >> That's a cute acronym for 'Design pattern aficionados Reinventing
    >> elementary database theorY' (in short: Databases should not contain
    >> redundant copies of the same data to avoid so-called 'update
    >> anomalies', the database becoming inconsistent because not all
    >> redudant copies of 'some data' are changed during an update. People
    >> usually ignore that in favor of 'nobdoy will ever update X without
    >> going to gatekeeper code Z which always keeps all copies in sync' and
    >> looking dedicatedly in another direction whenever somebody mentions
    >> that 'updates withoug going throug Z' are possible. This could almost
    >> be called 'a basic design principle of modern Linux distributions'
    >> :->).

    >
    > Um, what?


    You can get an explanation in more detail than I care to read at the
    moment here:

    http://en.wikipedia.org/wiki/Database_normalization

    If you strip out the technicalities relating to relational database
    management systems, you arrive at 'the DRY principle'.

    [...]

    >
    >> > use parent "Parent";
    >> > use slots qw/one two three/;
    >> >
    >> > in that order, @{ caller . "::ISA" } will contain the direct parents at
    >> > this point. You can also croak if they're trying to use MI.

    >>
    >> I thought about that and decided against it: This would require @ISA
    >> to be populated by the time the import method is executed and the code
    >> would either need to operate in 'pushy nanny mode' ("I've told you you
    >> must not inherit methods from more than one class and you must do as I say
    >> because I say so!") or make a guess at which of the possibly many
    >> direct and indirect(!) 'superclasses' is supposed to be the anchoring
    >> point for the new slot name series. But in reality, @ISA is about
    >> method lookups and not about 'allocating array slots in a
    >> non-conflicting way to members of some "inheritance tree"'.
    >>
    >> One can assume that packages sharing an array reference for instance
    >> data will usually also share method via @ISA but this need not be
    >> true.

    >
    > I suppose; certainly a facility to inherit slots independently of @ISA
    > might be useful. Data and method inheritance staying in sync must be the
    > overwhelmingly common case, though, so optimising the 'use' interface
    > for that would seem sensible.


    The issue is really that the @ISA array has a defined meaning: It is
    used to facilitate subroutine sharing outside of the normal export/
    import mechanism. This can be envisioned as being "a feeble/ strange
    way to declare 'class ancestor/ descendant' relationships" and it is
    usually even referred to as such but this is just 'a notational
    convenience' and it really isn't something like this.

    Eg, the most common case of 'multiple inheritance' I'm presently
    dealing with is a package named 'Thing' and all it provides is an
    overloaded ""-operation which prints the package some reference is
    blessed into, followed by the refaddr, followed by a 'tag' of some
    kind in []. A package which wants to inherit this "" needs to provide
    a tag method returning a tag and the Thing package maintains a cache
    of 'object tags' in a package-global hash. This is supposed to make
    diagnostic messages more intelligible and the provided functionality
    is independent of any properties of packages 'inheriting' from Thing.

    >> Also just because some package is listed in @ISA doesn't
    >> necessarily mean that it should also participiate in the 'data
    >> inheritance hierarchy'. These are orthogonal issues and one of the
    >> serious drawbacks of many existing 'OO support modules' is that the
    >> authors usually fell prey to their own "Jack of all trades" desires
    >> and 'hard-coded' technically independent policy choices they usually
    >> happen to make in their code.


    'Optimising for the common case' is really the same as 'hardcoding
    technically unrelated policy choices' because someone considered them
    "overwhelmingly important" or even "the only Right choice" or so but
    in practice, this still just means "How I happen would have done
    that" and how justified the generalization actually is is usally
    unknown.

    Some people consider 'make the right policy ch

    [...]

    >> >> @_ = ($_[0], {map { $_, $ctr++; } @$fields});
    >> >
    >> > Strictly this should be "constant" rather than $_[0] (which will be
    >> > "slots"), since this is supposed to be emulating constant->import. In
    >> > fact constant.pm doesn't care, but in principle it might care at some
    >> > point in the future.

    >>
    >> It would be 'constant' if constant::import had actually been
    >> invoked directly. But since this isn't the case and no 'requirements
    >> specification' of any kind exists (as far as I'm aware of that)
    >> anything would do insofar it pushes the first 'actual argument' to
    >> $_[1].

    >
    > The only documented interface to constant.pm is via 'use'. This will
    > call constant::import with $_[0] = "constant", so that is an implicit
    > part of the 'requirements specification' for using constant.pm.


    'Implicit [part of] the specification' is a contradiction in
    adiecto. When invoking constant::import via use, the first argument
    happens to be 'constant'. Since nothing is documented about invoking
    constant::import in any other situation, no information regarding what
    the first argument is supposed to be then is available. One can argue
    that the conservative choice would be to pass 'constant' as first
    argument,


    > It's only by chance that constant::import happens to ignore its first
    > argument:


    but given the code is written in the way it is, this isn't really
    needed.

    NB: The obvious counterargument would be that using goto & to hide
    the caller but then pass information about it to the called routine
    nevertheless is 'internally add odds with itself' but I just felt a
    bit 'full disclosure anarchistic' when writing the code.

    [...]

    >>> It's not a bad idea; it's basically the same as Class::Accessor::Faster
    >>> or MooseX::ArrayRef.

    >>
    >> I assume the authors of the two named modules would calls this 'a
    >> backhanded compliment' (and rightly so :->) and so would I (also
    >> rightly so :->). This is a slight generalization of an anonymous array
    >> sharing scheme I've been using since 199x and it really doesn't (and
    >> shouldn't) do anything except solve this particular problem.

    >
    > I was trying to be polite.


    But you were actually impolite in all directions: Both modules you
    named are supposed to provide 'something completely different' and in
    the case of Class:: it isn't even clear (to me, at least) whether
    this involves using anonymous arrays as object representation at all.
    I was trying to be polite by formulating this in this way instead of
    just pointing out that I strongly disagree with 'certain
    implementation choices' implicit in Class:: and Moose::antyhing and
    really don't appreciate something sensible I wrote being dragged into
    these pits.

    > You were presenting it as a revelation the like of which Perl had
    > never seen before;


    I presented a scheme for manageing array slots in shared, anonymous
    arrays and while this scheme is very simple, it is useful and it hasn't
    (to the best of my knowledge) been published in some 'canned',
    ready-to-use form so far (except maybe as 'minor internal part' of
    another Wolpertinger-module). Also, minus a few hints in the Perl
    documentation, I'm not aware of any actual discussion of the
    advantages and disadvantages of using different kinds of Perl objects
    as object representation.

    > in fact, it's a rather obvious idea, with very few advantages over
    > standard hashref-based objects, and some important disadvantages.
    > In some specific situations, in particular where saving memory is
    > important, it might be useful, but for general use it doesn't seem
    > to me worth expending effort trying to work around the problems with
    > arrayref objects unless you want to do a complete job and solve all
    > the problems.


    Please feel free to argue against the points in favour of using
    anonymous arrays for object representation and against using anonymous
    hashes I made. I consider them sound but argueing against them should
    certainly be possible. The 'summary judgement plus hand-waiving' above
    isn't useful for anyone trying to make an informed descision
    himself. We already had 'one million flies' aka 'the standard way' aka
    'but everyone [I consider relevant] does it that way' -- that's a
    logical fallacy also known as 'ad populum' fallacy,

    http://www.skepdic.com/adpopulum.html

    and even your somewhat repetitive insistence of generalizing each
    specific problem situation until the specific solution to that no
    longer suits the expanded problem is sort-of a 'well-known'
    'discussion technology' of less-than-excellent reputation,

    http://www.whale.to/m/disin.html

    in particular, 12/14 (and maybe 8 for the 'qualitative summary
    judgement' trick).

    [...]

    >> This 'anonymous array sharing scheme' might not be useful
    >> to solve 'certain problems' or might only be a component which could
    >> be employed for solving them. But that's a different conversation (I
    >> already wrote about the
    >> washer-dryer-lawnmower-bicycle-tophat-eggwarmer-hovercraft-theodolite
    >> ... sometimes, a hammer is really the right tool).

    >
    > Sometimes, yes. Most of those times, I'd just use an arrayref directly,
    > and probably not even bother with the constants.


    Using magic, numerical values in code is something which should - in
    my opinion - almost always be avoided, especially so if the actual
    numerical values have no relation to their use (eg, for an anonymous
    array used as object representation, it usuallg doesn't matter which
    'instance property' is associated with which slot number).
    Rainer Weikusat, Mar 19, 2013
    #3
  4. Ben Morrow <> writes:
    > Quoth Rainer Weikusat <>:
    >> Ben Morrow <> writes:
    >> > Quoth Rainer Weikusat <>:
    >> >> Ben Morrow <> writes:

    >>
    >> >> > You can look up the inheritance here instead of having the user specify
    >> >> > it (DRY and all that...). As long as they
    >> >>
    >> >> Re: DRY
    >> >>
    >> >> That's a cute acronym for 'Design pattern aficionados Reinventing
    >> >> elementary database theorY' (in short: Databases should not contain
    >> >> redundant copies of the same data to avoid so-called 'update
    >> >> anomalies', the database becoming inconsistent because not all
    >> >> redudant copies of 'some data' are changed during an update. People
    >> >> usually ignore that in favor of 'nobdoy will ever update X without
    >> >> going to gatekeeper code Z which always keeps all copies in sync' and
    >> >> looking dedicatedly in another direction whenever somebody mentions
    >> >> that 'updates withoug going throug Z' are possible. This could almost
    >> >> be called 'a basic design principle of modern Linux distributions'
    >> >> :->).
    >> >
    >> > Um, what?

    >>
    >> You can get an explanation in more detail than I care to read at the
    >> moment here:
    >>
    >> http://en.wikipedia.org/wiki/Database_normalization

    >
    > Yes, I know what database normalisation is. I don't see what relevance
    > it has here, nor what relevance the design of Linux distros has.
    >
    >> If you strip out the technicalities relating to relational database
    >> management systems, you arrive at 'the DRY principle'.

    >
    > So? I assume you're trying to make a point, rather than just talking to
    > hear yourself speak, but I can't see what it might be.


    And I 'assume' that the point of this 'snide remark' is - well - being
    a snide remark.

    >> >> > use parent "Parent";
    >> >> > use slots qw/one two three/;
    >> >> >
    >> >> > in that order, @{ caller . "::ISA" } will contain the direct parents at
    >> >> > this point. You can also croak if they're trying to use MI.
    >> >>
    >> >> I thought about that and decided against it: This would require @ISA
    >> >> to be populated by the time the import method is executed and the code
    >> >> would either need to operate in 'pushy nanny mode' ("I've told you you
    >> >> must not inherit methods from more than one class and you must do as I say
    >> >> because I say so!") or make a guess at which of the possibly many
    >> >> direct and indirect(!) 'superclasses' is supposed to be the anchoring
    >> >> point for the new slot name series. But in reality, @ISA is about
    >> >> method lookups and not about 'allocating array slots in a
    >> >> non-conflicting way to members of some "inheritance tree"'.
    >> >>
    >> >> One can assume that packages sharing an array reference for instance
    >> >> data will usually also share method via @ISA but this need not be
    >> >> true.
    >> >
    >> > I suppose; certainly a facility to inherit slots independently of @ISA
    >> > might be useful. Data and method inheritance staying in sync must be the
    >> > overwhelmingly common case, though, so optimising the 'use' interface
    >> > for that would seem sensible.

    >>
    >> The issue is really that the @ISA array has a defined meaning: It is
    >> used to facilitate subroutine sharing outside of the normal export/
    >> import mechanism.

    >
    > No, it's used to implement method dispatch. This is quite different from
    > sub sharing; for one thing, it uses a different call syntax.


    Call this anything you like but it enables more than one 'package'
    (call that 'class' if you like) to execute the same subroutine in
    response to a so-called 'method call' and not about 'data
    inheritance'.

    >> This can be envisioned as being "a feeble/ strange
    >> way to declare 'class ancestor/ descendant' relationships" and it is
    >> usually even referred to as such but this is just 'a notational
    >> convenience' and it really isn't something like this.
    >>
    >> Eg, the most common case of 'multiple inheritance' I'm presently
    >> dealing with is a package named 'Thing' and all it provides is an
    >> overloaded ""-operation which prints the package some reference is
    >> blessed into, followed by the refaddr, followed by a 'tag' of some
    >> kind in []. A package which wants to inherit this "" needs to provide
    >> a tag method returning a tag and the Thing package maintains a cache
    >> of 'object tags' in a package-global hash. This is supposed to make
    >> diagnostic messages more intelligible and the provided functionality
    >> is independent of any properties of packages 'inheriting' from Thing.

    >
    > This technique is called 'mixins' (at least, it is in the Perl
    > world),


    [digression removed]

    For the situation at hand, it was an example of a package listed in
    @ISA which is not supposed to be part of the 'data inheritance
    hierarchy'.

    >> >> Also just because some package is listed in @ISA doesn't
    >> >> necessarily mean that it should also participiate in the 'data
    >> >> inheritance hierarchy'. These are orthogonal issues and one of the
    >> >> serious drawbacks of many existing 'OO support modules' is that the
    >> >> authors usually fell prey to their own "Jack of all trades" desires
    >> >> and 'hard-coded' technically independent policy choices they usually
    >> >> happen to make in their code.

    >>
    >> 'Optimising for the common case' is really the same as 'hardcoding
    >> technically unrelated policy choices' because someone considered them
    >> "overwhelmingly important" or even "the only Right choice" or so but
    >> in practice, this still just means "How I happen would have done
    >> that" and how justified the generalization actually is is usally
    >> unknown.

    >
    > Optimising for the common case doesn't mean making functionality
    > unavailable, it just means making the 'easy' interface work the way you
    > usually want it to.


    In the given case, the 'easy' interface does work in the way 'I
    usually want it to' because I usually don't 'want' to force policy
    descisions which seem sensible to me onto others. Not the least
    because I would be forcing them onto myself first and they wouldn't be
    suitable for my use case.

    [...]

    >> But you were actually impolite in all directions: Both modules you
    >> named are supposed to provide 'something completely different' and in
    >> the case of Class:: it isn't even clear (to me, at least) whether
    >> this involves using anonymous arrays as object representation at all.

    >
    > It does. Class::Accessor::Faster provides almost exactly the same as
    > slots: it gives you a constructor, and accessors, for an arrayref-based
    > object, and nothing else.


    Compared to a 'pragamatic module' which provides a way to allocate
    'array slot numbers' in a way suitable for using an anonymous array as
    'object instance representation with data sharing' among members of
    single-inheritance class hierarchy, that's something 'almost
    completely different' except for the (irrelevant) implementation
    detail that 'anonymous arrays' might also be used by Class::.

    >> I was trying to be polite by formulating this in this way instead
    >> of just pointing out that I strongly disagree with 'certain
    >> implementation choices' implicit in Class:: and Moose::antyhing and
    >> really don't appreciate something sensible I wrote being dragged
    >> into these pits.

    >
    > So you have said, though you have yet to explain your disagreement
    > beyond


    [snide remark deleted]

    >> I presented a scheme for manageing array slots in shared, anonymous
    >> arrays and while this scheme is very simple, it is useful and it hasn't
    >> (to the best of my knowledge) been published in some 'canned',
    >> ready-to-use form so far (except maybe as 'minor internal part' of
    >> another Wolpertinger-module).

    >
    > Had you cared to look, you would have found that CAF is pretty-much
    > exactly the same thing.


    It may be 'pretty much the same thing' in your opinion but this is an
    opinion I don't share.

    [more irrelevant stuff deleted]

    >> > in fact, it's a rather obvious idea, with very few advantages over
    >> > standard hashref-based objects, and some important disadvantages.
    >> > In some specific situations, in particular where saving memory is
    >> > important, it might be useful, but for general use it doesn't seem
    >> > to me worth expending effort trying to work around the problems with
    >> > arrayref objects unless you want to do a complete job and solve all
    >> > the problems.

    >>
    >> Please feel free to argue against the points in favour of using
    >> anonymous arrays for object representation and against using anonymous
    >> hashes I made. I consider them sound but argueing against them should
    >> certainly be possible.

    >
    > I have given some of the disadvantages already:
    >
    > - Inheriting attributes from more than one parent, by any means, is
    > more difficult to get right;


    As I already wrote a couple of times: This is for single-inheritance
    hierarchies. Consequently, the fact that it really isn't suitable for
    'class hetarchies' is no more a disadvantage of this scheme than it is
    'a disadvantage' of a car that it can't fly or swim: It isn't
    supposed to.

    > - Changing the attributes of a class at runtime (including changing
    > the inheritance) will cause existing compiled methods to refer to
    > the wrong attributes;


    I understand this as "code could be written with the explicit
    intention to break this and then, it would break". Which isn't exactly
    a surprise and holds for all code.

    [yet more irrelevant stuff deleted]

    BTW, if I had any talent as graphical artist (which I unforuntately
    don't), I would scan the cover of the camel book, would decorate
    the head of the poor beast with a pair of gigantic antlers (maybe with
    some dripping bits of water plants of them) and would publish this as
    a 'Remove doesn't fit into this picture' cartoon. I figure that
    would leave you with a pair of antlers hanging in the air for no
    particular reason and me with a camel. Just to return one of the snide
    remarks.
    Rainer Weikusat, Mar 20, 2013
    #4
  5. Ben Morrow <> writes:
    > Quoth Rainer Weikusat <>:
    >> Ben Morrow <> writes:
    >> > Quoth Rainer Weikusat <>:
    >> >> Ben Morrow <> writes:

    >>
    >> >> > You can look up the inheritance here instead of having the user specify
    >> >> > it (DRY and all that...). As long as they
    >> >>
    >> >> Re: DRY
    >> >>
    >> >> That's a cute acronym for 'Design pattern aficionados Reinventing
    >> >> elementary database theorY' (in short: Databases should not contain
    >> >> redundant copies of the same data to avoid so-called 'update
    >> >> anomalies', the database becoming inconsistent because not all
    >> >> redudant copies of 'some data' are changed during an update. People
    >> >> usually ignore that in favor of 'nobdoy will ever update X without
    >> >> going to gatekeeper code Z which always keeps all copies in sync' and
    >> >> looking dedicatedly in another direction whenever somebody mentions
    >> >> that 'updates withoug going throug Z' are possible. This could almost
    >> >> be called 'a basic design principle of modern Linux distributions'
    >> >> :->).
    >> >
    >> > Um, what?

    >>
    >> You can get an explanation in more detail than I care to read at the
    >> moment here:
    >>
    >> http://en.wikipedia.org/wiki/Database_normalization

    >
    > Yes, I know what database normalisation is. I don't see what relevance
    > it has here, nor what relevance the design of Linux distros has.
    >
    >> If you strip out the technicalities relating to relational database
    >> management systems, you arrive at 'the DRY principle'.

    >
    > So? I assume you're trying to make a point, rather than just talking to
    > hear yourself speak, but I can't see what it might be.


    And I 'assume' that the point of this 'snide remark' is - well - being
    a snide remark.

    >> >> > use parent "Parent";
    >> >> > use slots qw/one two three/;
    >> >> >
    >> >> > in that order, @{ caller . "::ISA" } will contain the direct parents at
    >> >> > this point. You can also croak if they're trying to use MI.
    >> >>
    >> >> I thought about that and decided against it: This would require @ISA
    >> >> to be populated by the time the import method is executed and the code
    >> >> would either need to operate in 'pushy nanny mode' ("I've told you you
    >> >> must not inherit methods from more than one class and you must do as I say
    >> >> because I say so!") or make a guess at which of the possibly many
    >> >> direct and indirect(!) 'superclasses' is supposed to be the anchoring
    >> >> point for the new slot name series. But in reality, @ISA is about
    >> >> method lookups and not about 'allocating array slots in a
    >> >> non-conflicting way to members of some "inheritance tree"'.
    >> >>
    >> >> One can assume that packages sharing an array reference for instance
    >> >> data will usually also share method via @ISA but this need not be
    >> >> true.
    >> >
    >> > I suppose; certainly a facility to inherit slots independently of @ISA
    >> > might be useful. Data and method inheritance staying in sync must be the
    >> > overwhelmingly common case, though, so optimising the 'use' interface
    >> > for that would seem sensible.

    >>
    >> The issue is really that the @ISA array has a defined meaning: It is
    >> used to facilitate subroutine sharing outside of the normal export/
    >> import mechanism.

    >
    > No, it's used to implement method dispatch. This is quite different from
    > sub sharing; for one thing, it uses a different call syntax.


    Call this anything you like but it enables more than one 'package'
    (call that 'class' if you like) to execute the same subroutine in
    response to a so-called 'method call' and not about 'data
    inheritance'.

    >> This can be envisioned as being "a feeble/ strange
    >> way to declare 'class ancestor/ descendant' relationships" and it is
    >> usually even referred to as such but this is just 'a notational
    >> convenience' and it really isn't something like this.
    >>
    >> Eg, the most common case of 'multiple inheritance' I'm presently
    >> dealing with is a package named 'Thing' and all it provides is an
    >> overloaded ""-operation which prints the package some reference is
    >> blessed into, followed by the refaddr, followed by a 'tag' of some
    >> kind in []. A package which wants to inherit this "" needs to provide
    >> a tag method returning a tag and the Thing package maintains a cache
    >> of 'object tags' in a package-global hash. This is supposed to make
    >> diagnostic messages more intelligible and the provided functionality
    >> is independent of any properties of packages 'inheriting' from Thing.

    >
    > This technique is called 'mixins' (at least, it is in the Perl
    > world),


    [digression removed]

    For the situation at hand, it was an example of a package listed in
    @ISA which is not supposed to be part of the 'data inheritance
    hierarchy'.

    >> >> Also just because some package is listed in @ISA doesn't
    >> >> necessarily mean that it should also participiate in the 'data
    >> >> inheritance hierarchy'. These are orthogonal issues and one of the
    >> >> serious drawbacks of many existing 'OO support modules' is that the
    >> >> authors usually fell prey to their own "Jack of all trades" desires
    >> >> and 'hard-coded' technically independent policy choices they usually
    >> >> happen to make in their code.

    >>
    >> 'Optimising for the common case' is really the same as 'hardcoding
    >> technically unrelated policy choices' because someone considered them
    >> "overwhelmingly important" or even "the only Right choice" or so but
    >> in practice, this still just means "How I happen would have done
    >> that" and how justified the generalization actually is is usally
    >> unknown.

    >
    > Optimising for the common case doesn't mean making functionality
    > unavailable, it just means making the 'easy' interface work the way you
    > usually want it to.


    In the given case, the 'easy' interface does work in the way 'I
    usually want it to' because I usually don't 'want' to force policy
    descisions which seem sensible to me onto others. Not the least
    because I would be forcing them onto myself first and they wouldn't be
    suitable for my use case.

    [...]

    >> But you were actually impolite in all directions: Both modules you
    >> named are supposed to provide 'something completely different' and in
    >> the case of Class:: it isn't even clear (to me, at least) whether
    >> this involves using anonymous arrays as object representation at all.

    >
    > It does. Class::Accessor::Faster provides almost exactly the same as
    > slots: it gives you a constructor, and accessors, for an arrayref-based
    > object, and nothing else.


    Compared to a 'pragamatic module' which provides a way to allocate
    'array slot numbers' in a way suitable for using an anonymous array as
    'object instance representation with data sharing' among members of
    single-inheritance class hierarchy, that's something 'almost
    completely different' except for the (irrelevant) implementation
    detail that 'anonymous arrays' might also be used by Class::.

    >> I was trying to be polite by formulating this in this way instead
    >> of just pointing out that I strongly disagree with 'certain
    >> implementation choices' implicit in Class:: and Moose::antyhing and
    >> really don't appreciate something sensible I wrote being dragged
    >> into these pits.

    >
    > So you have said, though you have yet to explain your disagreement
    > beyond


    [snide remark deleted]

    >> I presented a scheme for manageing array slots in shared, anonymous
    >> arrays and while this scheme is very simple, it is useful and it hasn't
    >> (to the best of my knowledge) been published in some 'canned',
    >> ready-to-use form so far (except maybe as 'minor internal part' of
    >> another Wolpertinger-module).

    >
    > Had you cared to look, you would have found that CAF is pretty-much
    > exactly the same thing.


    It may be 'pretty much the same thing' in your opinion but this is an
    opinion I don't share.

    [more irrelevant stuff deleted]

    >> > in fact, it's a rather obvious idea, with very few advantages over
    >> > standard hashref-based objects, and some important disadvantages.
    >> > In some specific situations, in particular where saving memory is
    >> > important, it might be useful, but for general use it doesn't seem
    >> > to me worth expending effort trying to work around the problems with
    >> > arrayref objects unless you want to do a complete job and solve all
    >> > the problems.

    >>
    >> Please feel free to argue against the points in favour of using
    >> anonymous arrays for object representation and against using anonymous
    >> hashes I made. I consider them sound but argueing against them should
    >> certainly be possible.

    >
    > I have given some of the disadvantages already:
    >
    > - Inheriting attributes from more than one parent, by any means, is
    > more difficult to get right;


    As I already wrote a couple of times: This is for single-inheritance
    hierarchies. Consequently, the fact that it really isn't suitable for
    'class hetarchies' is no more a disadvantage of this scheme than it is
    'a disadvantage' of a car that it can't fly or swim: It isn't
    supposed to.

    > - Changing the attributes of a class at runtime (including changing
    > the inheritance) will cause existing compiled methods to refer to
    > the wrong attributes;


    I understand this as "code could be written with the explicit
    intention to break this and then, it would break". Which isn't exactly
    a surprise and holds for all code.

    [yet more irrelevant stuff deleted]

    BTW, if I had any talent as graphical artist (which I unforuntately
    don't), I would scan the cover of the camel book, would decorate
    the head of the poor beast with a pair of gigantic antlers (maybe with
    some dripping bits of water plants on them) and would publish this as
    a 'Remove wha doesn't fit into this picture' cartoon. I figure that
    would leave you with a pair of antlers hanging in the air for no
    particular reason and me with a camel. Just to return one of the snide
    remarks.
    Rainer Weikusat, Mar 20, 2013
    #5
  6. Rainer Weikusat

    C.DeRykus Guest

    On Friday, March 15, 2013 1:05:44 PM UTC-7, Rainer Weikusat wrote:
    > ...
    > A possible way would be to prefix the package name to each property
    >
    > name and hope that all other packages also do this. But since package
    >
    > names are often longish, this is an unwiedly workaround. A workaround
    >
    > for the workaround would be to use declared constants whose values are
    >
    > the long property names and whose names are short enough to be used
    >
    > comfortably. But - alas - the {} autoquotes the key if it 'looks like
    >
    > a string' and this means that
    >


    >
    > use constant NAME => __PACKAGE__.'name';
    >
    >
    >
    > $h->{NAME} = 'Paul';
    >
    > doesn't work. A workaround for the workaround for the workaround would
    >
    > be to invoke the 'constant subroutine' explicitly,
    >
    >
    >
    > $h->{NAME()} = 'Paul';
    >
    >
    > but the two added noise characters are rather ugly.
    >


    Maybe a sightly prettier workaround for auto-quoting
    and all the sub calls...

    use CONSTANT NAME => __PACKAGE__ . 'name';
    $h->{+NAME} = 'Paul';

    --> $VAR1 = {
    'main::name' => 'Paul'
    };


    >
    > Lastly, the hash lookup which is a rather costly operation happens
    >
    > every time such a named property is accessed.


    > ...


    --
    Charles DeRykus
    C.DeRykus, Mar 23, 2013
    #6
  7. "C.DeRykus" <> writes:
    > On Friday, March 15, 2013 1:05:44 PM UTC-7, Rainer Weikusat wrote:


    [...]

    >> use constant NAME => __PACKAGE__.'name';
    >>
    >> $h->{NAME} = 'Paul';
    >>
    >> doesn't work. A workaround for the workaround for the workaround would

    > be to invoke the 'constant subroutine' explicitly,
    >>
    >> $h->{NAME()} = 'Paul';


    [...]

    > Maybe a sightly prettier workaround for auto-quoting
    > and all the sub calls...
    >
    > use CONSTANT NAME => __PACKAGE__ . 'name';
    > $h->{+NAME} = 'Paul';


    Something which also works, although I'm not sure if this is
    intentional:

    $h->{NAME,}
    Rainer Weikusat, Mar 23, 2013
    #7
  8. Rainer Weikusat <> writes:
    > "C.DeRykus" <> writes:
    >> On Friday, March 15, 2013 1:05:44 PM UTC-7, Rainer Weikusat wrote:

    >
    > [...]
    >
    >>> use constant NAME => __PACKAGE__.'name';
    >>>
    >>> $h->{NAME} = 'Paul';
    >>>
    >>> doesn't work. A workaround for the workaround for the workaround would

    >> be to invoke the 'constant subroutine' explicitly,
    >>>
    >>> $h->{NAME()} = 'Paul';

    >
    > [...]
    >
    >> Maybe a sightly prettier workaround for auto-quoting
    >> and all the sub calls...
    >>
    >> use CONSTANT NAME => __PACKAGE__ . 'name';
    >> $h->{+NAME} = 'Paul';

    >
    > Something which also works, although I'm not sure if this is
    > intentional:
    >
    > $h->{NAME,}


    .... but this is generally not a good idea (which leads to another
    disadvantage of hashes for emulating structures): Since $h->{NAME} is
    a valid expression in its own right, accidentally omitting the , (or
    +) possibly means using an 'unintended' key for storing or accessing a
    certain property. A similar issue exists for 'plain string keys'
    because a name with a typo is as good a hash key as any other
    string. Since 'objects properties' are really nothing but a
    generalization of 'global variable sets'[*], that is 'modifiable objects
    multiple cooperating subsroutines used for storing shared state
    information', this becomes especially nasty when dealing with code
    written by someone else ('someone else' here includes 'code one has
    written oneself some months or even years ago'): The only way to
    determine if a particular instance of

    $h->{some_name}

    is using the intended key string or an erroneous one is to examine all
    code which might use the object in order to find all 'similar keys'
    and then make an educated guess based on the information determined in
    this way. Yet another 'similar problem' exists for 'accessor methods'
    because lookup of these is also based on searching for a string key in
    some set of hash tables: An accidentally misspelled method on a rarely
    executed codepath will go unnoticed until this codepath is executed
    and then, a fatal runtime error will occur.

    In contrast to this, declaring property names as constants and using
    these constant for accessing array slots implies that misspellings etc
    will cause compile-time errors (when using strict as part of the
    compilation).

    [*] Another fact 'many people' who pay very demonstrative lip service to
    "global variables are BAD" refuse to understand (Or claim to be
    unable to understand. I haven't yet made up my mind on whether this is
    a genuine incapability to see structural similarities in superficially
    different things or a case of 'playing dumb' in the hope that
    'stubborn denial' combined with 'suitable' personal attacks will at
    least be sufficient to confuse someone).
    Rainer Weikusat, Mar 24, 2013
    #8
  9. Rainer Weikusat

    C.DeRykus Guest

    On Sunday, March 24, 2013 7:11:10 AM UTC-7, Rainer Weikusat wrote:
    > Rainer Weikusat <> writes:
    >
    > > "C.DeRykus" <> writes:

    >
    > >> On Friday, March 15, 2013 1:05:44 PM UTC-7, Rainer Weikusat wrote:

    >
    > >

    >
    > > [...]

    >
    > >

    >
    > >>> use constant NAME => __PACKAGE__.'name';

    >
    > >>>

    >
    > >>> $h->{NAME} = 'Paul';

    >
    > >>>

    >
    > >>> doesn't work. A workaround for the workaround for the workaround would

    >
    > >> be to invoke the 'constant subroutine' explicitly,

    >
    > >>>

    >
    > >>> $h->{NAME()} = 'Paul';

    >
    > >

    >
    > > [...]

    >
    > >

    >
    > >> Maybe a sightly prettier workaround for auto-quoting

    >
    > >> and all the sub calls...

    >
    > >>

    >
    > >> use CONSTANT NAME => __PACKAGE__ . 'name';

    >
    > >> $h->{+NAME} = 'Paul';

    >
    > >

    >
    > > Something which also works, although I'm not sure if this is

    >
    > > intentional:

    >
    > >

    >
    > > $h->{NAME,}

    >
    >
    >
    > ... but this is generally not a good idea (which leads to another
    >
    > disadvantage of hashes for emulating structures): Since $h->{NAME} is
    >
    > a valid expression in its own right, accidentally omitting the , (or
    >
    > +) possibly means using an 'unintended' key for storing or accessing a
    >
    > certain property. A similar issue exists for 'plain string keys'
    >
    > because a name with a typo is as good a hash key as any other
    >
    > string. Since 'objects properties' are really nothing but a
    >
    > generalization of 'global variable sets'[*], that is 'modifiable objects
    >
    > multiple cooperating subsroutines used for storing shared state
    >
    > information', this becomes especially nasty when dealing with code
    >
    > written by someone else ('someone else' here includes 'code one has
    >
    > written oneself some months or even years ago'): The only way to
    >
    > determine if a particular instance of
    >
    >
    >
    > $h->{some_name}
    >
    >
    >
    > is using the intended key string or an erroneous one is to examine all
    >
    > code which might use the object in order to find all 'similar keys'
    >
    > and then make an educated guess based on the information determined in
    >
    > this way. Yet another 'similar problem' exists for 'accessor methods'
    >
    > because lookup of these is also based on searching for a string key in
    >
    > some set of hash tables: An accidentally misspelled method on a rarely
    >
    > executed codepath will go unnoticed until this codepath is executed
    >
    > and then, a fatal runtime error will occur.
    >
    >
    >
    > In contrast to this, declaring property names as constants and using
    >
    > these constant for accessing array slots implies that misspellings etc
    >
    > will cause compile-time errors (when using strict as part of the
    >
    > compilation).
    >
    > ...


    I regretted the post almost immediately for several reasons.

    However, I was surprised by these exceptions to these hash key
    auto-quoting twists. It seems very odd that the trailing ","
    (multi-dimensional array emulation) would work at all. Ditto
    for the pre-pended "+". No idea why.

    --
    Charles DeRykus
    array emulation)
    to cause multi-dim. emulation
    C.DeRykus, Mar 25, 2013
    #9
  10. Ben Morrow wrote:
    >
    > The one thing that is slightly weird is that $h{NAME,} calls NAME in
    > scalar context, despite the comma.


    The comma has no effect on context. NAME, is inside $h{} and $h{} is a
    scalar (see the $ sigil). If you had used a hash slice like @h{NAME,}
    then NAME would be in list context, with or without the comma.


    > I think what is happening here is
    > that the code which decides whether this is a single- or multi-dim
    > subscript just looks at the number of expressions in its argument list,
    > by which time that comma has long since disappeared.



    John
    --
    Any intelligent fool can make things bigger and
    more complex... It takes a touch of genius -
    and a lot of courage to move in the opposite
    direction. -- Albert Einstein
    John W. Krahn, Mar 25, 2013
    #10
  11. Rainer Weikusat

    C.DeRykus Guest

    On Sunday, March 24, 2013 11:05:41 PM UTC-7, Ben Morrow wrote:
    > Quoth "C.DeRykus" <>:
    >
    > >

    >
    > > I regretted the post almost immediately for several reasons.

    >
    > >

    >
    > > However, I was surprised by these exceptions to these hash key

    >
    > > auto-quoting twists. It seems very odd that the trailing ","

    >
    > > (multi-dimensional array emulation) would work at all. Ditto

    >
    > > for the pre-pended "+". No idea why.

    >
    >
    >
    > Anything inside the {} which doesn't match \w causes the contents to be
    >
    > interpreted as an expression rather than a string. C<+NAME> and C<NAME,>
    >
    > are both perfectly valid expressions which call the sub NAME: the + is
    >
    > the unary 'term' operator, which does exactly nothing and is
    >
    > occasionally useful to persuade Perl to choose one interpretation of an
    >
    > ambiguous expression rather than another;the , is an ordinary trailing-comma-on-the-end-of-a-list, which is eaten by the parser and doesn't add
    >
    > an extra element.
    >
    >
    > The one thing that is slightly weird is that $h{NAME,} calls NAME in
    >
    > scalar context, despite the comma. I think what is happening here is
    >
    > that the code which decides whether this is a single- or multi-dim
    >
    > subscript just looks at the number of expressions in its argument list,
    >
    > by which time that comma has long since disappeared.
    >



    Thanks for the insights. I actually knew "+" was a "persuader"
    but had forgotten I saw this in the doc:

    Use $hash{CONSTANT()} or $hash{+CONSTANT} to
    prevent the bareword quoting mechanism from kicking in.

    --
    Charles DeRykus
    C.DeRykus, Mar 25, 2013
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Joona I Palaste

    Needless casts?

    Joona I Palaste, Apr 24, 2004, in forum: Java
    Replies:
    15
    Views:
    686
    Icemerth
    Apr 25, 2004
  2. shanx__=|;-

    very very very long integer

    shanx__=|;-, Oct 16, 2004, in forum: C Programming
    Replies:
    19
    Views:
    1,613
    Merrill & Michele
    Oct 19, 2004
  3. Abhishek Jha

    very very very long integer

    Abhishek Jha, Oct 16, 2004, in forum: C Programming
    Replies:
    4
    Views:
    417
    jacob navia
    Oct 17, 2004
  4. James Stroud

    Needless copying in iterations?

    James Stroud, Sep 15, 2007, in forum: Python
    Replies:
    22
    Views:
    632
    =?ISO-8859-1?Q?BJ=F6rn_Lindqvist?=
    Sep 17, 2007
  5. Jukka Lahtinen
    Replies:
    1
    Views:
    887
    Jukka Lahtinen
    Feb 24, 2011
Loading...

Share This Page