Re: Curious: are anon-hashes in random order? (updated)
by haukex (Archbishop) on Sep 13, 2016 at 15:00 UTC
|
use List::Util qw/shuffle/;
my @order = shuffle qw/ continue 0 next 1 redo 2 last 3 /;
What it means is this:
my @keyorder = shuffle qw/ continue next redo last /;
So constant will always define four subs, which return the value associated with each key in the hash. It is equivalent to the following code; the order in which the subs are defined does not matter. (By the way, I think that defining subs with the same name as those Perl builtins is likely to cause confusion later.)
sub continue () { 0 }
sub next () { 1 }
sub redo () { 2 }
sub last () { 3 }
I know the following would fail (because the RHS of the 'our $clist' won't be done at compile time):
Correct, but this would work:
our $clist;
BEGIN { $clist = {continue=>0, next=>1, redo=>2, last=>3 } }
use constant $clist;
But how is it that this seems to always work:
If I understand mem correctly, it's essentially doing the same thing as the code with the BEGIN block above. Also, remember that use Module LIST is exactly equivalent to BEGIN { require Module; Module->import( LIST ); }.
Is it that compile-time hashes are not randomized?
No, AFAIK Perl always iterates over hashes in a random order. No, you should always treat Perl hashes as being in a random order. Also, if you note the language for example in Hash overhaul, it says "the order which keys/values will be returned ... will differ from run to run". So it's not like hashes themselves are shuffled in memory, it's the order in which they are iterated over that is randomized. So this always happens at runtime, no matter where the hashes come from. Update: Struck/reworded these sentences as potentially misleading; see BrowserUk's reply below.
Hope this helps, -- Hauke D
| [reply] [d/l] [select] |
|
|
it's not like hashes themselves are shuffled in memory, it's the order in which they are iterated over that is randomized.
Actually, it is neither.
The "randomisation" takes the form of picking a single random number to seed the accumulator(*) when performing the hashing calculation for storing or retrieving the keys. Ie. by randomly initialising the accumulator, the position within the array that underlies the hash implementation, into which any given key gets stored, varies from hash to hash and run to run.
More importantly, the order in which the underlying array is iterated (first to last) when using each or keys or values is constant for all hashes and all runs -- thus very efficient. The randomisation occurs do to the addition of a (per hash, randomly chosen once) offset that gets added to all the hashing calculations and thus causes the same key to get stored in different slots for different hashes; and different slots for the same hash for different runs.
*there was, belatedly, some attempt to add a choice of different hashing algorithms to the mix; but these proved pointless overkill and pragmatically too inefficient; and fell into immediate disuse. If they are still needlessly cluttering the codebase -- I haven't looked lately -- it is simply because no one has got around to removing them.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
|
*the was, belatedly, some attempt to add a choice of different hashing algorithms to the mix; but these proved pointless overkill and pragmatically too inefficient; and fell into immediate disuse. If they are still needlessly cluttering the codebase -- I haven't looked lately -- it is simply because no one has got around to removing them
The above can be attributed to BrowserUk, and I was hoping to register the fact that I (syphilis) had given his view a ++ (and would have given even more upvotes if such were possible).
However, when I preview my post, I find that it is being attributed to gods.
What is going on ? (A "god" is the last fucking thing I would want to be ;-)
Cheers, Rob
| [reply] |
|
|
|
|
|
|
| [reply] |
|
|
So constant will always define four subs, which return the value associated with each key in the hash. It is equivalent to the following code; the order in which the subs are defined does not matter. (By the way, I think that defining subs with the same name as those Perl builtins is likely to cause confusion later.)
Never has in my usage -- you have to use the constants prefixed with '&' -- while putting '&' in front of those keywords is guaranteed to cause an error. So how could it cause confusion?
If I understand mem correctly, it's essentially doing the same thing as the code with the BEGIN block above. Also, remember that use Module LIST is exactly equivalent to BEGIN { require Module; Module->import( LIST ); }.
Well, as mentioned elsewhere, it's a side effect of perl, not really a feature of mem -- though mem supports the side-effect in perl by guaranteeing not to throw an error for that type of usage, making it an ideal candidate for the shorter usage.
mem's primary purpose was to allow packages that were already defined in a file to be "used" from the "in-memory" copy already parsed, rather than searching through your module path on disk, as is perl's default behavior. It allows easier inclusion of multiple "packages" in the same file -- which makes sense when the packages are related, meant to be data structures, or similar. Of course mem is only needed when you are 'use'ing the module vs. having the module function as a data structure.
When I declare struct's in perl, it takes about 3-4 lines (sorry, Data::Vars, is _still_ in my personal library and hasn't be cpanned yet -- stable, but publishing it would require alot of added tests and docs to be written), but using it is fairly simple:
> tperl # an alias
{ package foo;
use Data::Vars [qw(a b c) ], {c=>sub{ {} }}; #c gets a default
1}
package main;
my $p = foo->new({a=>1}); # a passed as arg
$p->b = [qw(one two three)]; # b assigned to at runtime
P "p=%s", $p; # and result
'
p=foo{a=>1, b=>["one", "two", "three"], c=>{}}
The primary purpose behind most of my modules is to simplify, save space and unnecessary typing. FWIW, 'c' is initialized with a sub around the hash so the same hash isn't assigned to each new copy of the data-structure.
| [reply] [d/l] [select] |
|
|
$ perl -MO=Deparse -e 'use constant c => 42; print c; print &c;'
sub c () { 42 }
use constant ('c', 42);
print 42;
print &c;
-e syntax OK
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] [select] |
|
|
Hi perl-diddler,
So how could it cause confusion?
You as the author may be able to keep track of the keywords vs. subs, and Perl may be able to resolve the ambiguity most of the time, but it's not too difficult to accidentally cross the line where Perl may pick the wrong definition (for example, there's the warning "Ambiguous call resolved as CORE::continue(), qualify as such or use & at ..."). Also, another reader of your code (including a future maintainer - or even your future self) could easily become confused between next and &next, etc.
It's just one of those cases where as long as you know what you are doing and your script isn't intended for distribution then it's probably fine; but if you do intend the code for a wider audience then I was just pointing out that there are some good rules of thumb / conventions, such as not to define subs with the same name as Perl builtins unless you intend to replace them, and that constant names are typically uppercased.
Regards, -- Hauke D
| [reply] [d/l] [select] |
|
|
Re: Curious: are anon-hashes in random order?
by stevieb (Canon) on Sep 13, 2016 at 13:28 UTC
|
constant takes a hash reference as its argument, and random order doesn't matter in this case, because each directive is named, not positional. There is no ambiguity.
constant puts its parameter (the hash ref) into a variable called $multiple on line 59, then on line 69, commences a check to see if the param is in fact a hash ref, and will croak if it isn't.
Further, this has nothing to do with the run phase either. You can't assign a hashref to a variable and then expect it to work in a use statement because the use is executed at compile time, but the hash is created at runtime. The reason your latter example works is because you're forcing $clist to be created prior to the use constant ... line by creating it at compile time one line above in another use statement. You could achieve the same thing with this:
my $clist;
BEGIN {
$clist = {a => 1, b => 2};
}
use constant $clist;
| [reply] [d/l] [select] |
|
|
my $clist;
BEGIN {
$clist = {a => 1, b => 2};
}
use constant $clist;
That's what I meant by being more 'expansive'... compared to
my $clist;
use <anymodule> ($clist = {a => 1, b => 2});
use constant $clist;
Note -- # anymodule, above, works for modules that are guaranteed to never cause some conflict with random assign statements in its argument list, like "mem".
It is a secondary use of mem, but still one that's useful
to know if you don't want to have your header/use/init area
littered w/compiler-keywords like BEGIN and indentation that sticks out like
a wart. Some people don't care about those things, some do. Chocolate or butterscotch, take your pick. ;-)
Of course all that could be handled in a greatly more straightforward manner if perl had a Macro facility like most compiler languages. While you can do similar w/perl using filters, my impression is that those are frowned upon, leaving no alternatives (or at least none that I'm aware of) :-(.
| [reply] [d/l] [select] |
Re: Curious: are anon-hashes in random order?
by Corion (Patriarch) on Sep 13, 2016 at 12:57 UTC
|
Where does the random order come into play?
constant defines/explains your use case IMO.
You could make things easier by posting self-contained Perl code that doesn't rely on multiple modules that don't seem to be necessary for operation. For example the definition of a shell alias doesn't seem to contribute and neither does the P module.
Maybe you can explain what you see that happens and what you think should happen instead.
Most likely, what you're seeing is that your mem module is equivalent to a simple BEGIN block.
| [reply] [d/l] |
|
|
I create my aliases and modules to simplify and shorten typing and thereby increase correctness.
If they aren't contained in CPAN (like the alias), I would include them.
It's so much more convenient to type 'tperl' when i want to test something in perl.
If you have an equivalent source case that is as simple and short, I'd be happy to use it, but perl tends toward being expansive. But demonstrating "use constants" without using any modules (when constants is a module) seems a bit impossible. Why would you try?
"Most likely, what you're seeing is that your mem module is equivalent to a simple BEGIN block."
Of course, but shorter. use mem wasn't the point. Anyone who knows intermediate perl would likely know that. I just don't like putting BEGIN{} blocks that 'should' be indented, in the middle of my module headers. use mem's primary use is to enable using a package in the same
file just like it would function in a separate file. The use mem(xxx) form is documented to make it official that anything you want to put in parens on the same line, is "OK" -- it won't cause a problem. I don't think other modules guarantee that. Since both involve bringing things "inline", I grouped them together in the same module.
It would be rather lame to come up with a module just to be able to safely init things at runtime -- that sole purpose was to guarantee the passed arguments would never cause an error in future code (by assigning some semantic meaning to the arglist passed to the module), don't you agree?
The point was that the hash isn't in random order...Ah... it's the pairs that are
in random order, now that makes more sense. I.e. if you print out the clist hash,
it's not in the order it was entered, but that doesn't matter as long as the pairs are
kept together. Was thinking about using a qw(continue 0 next 1 redo 2 last 3), as an
initializer but the randomness of hashes had me wondering why that worked -- but they'll
still be kept as pairs in any randomized hash...
| [reply] [d/l] [select] |
|
|
sub blah {
my %args = @_;
...
}
It simply takes the elements in order, assigning the first as the key and the second as the value until all elements have been assigned to the hash.
You can call the sub in numerous ways, and get the same result:
blah(qw(continue 0 next 1 redo 2 last 3));
blah('continue', 0, 'next', 1, 'redo', 2, 'last', 3);
blah(continue => 0, next => 1, redo => 2, last => 3);
my %h = (continue => 0, next => 1, redo => 2, last => 3);
blah(%h);
| [reply] [d/l] [select] |
Re: Curious: are anon-hashes in random order?
by Lotus1 (Vicar) on Sep 13, 2016 at 18:14 UTC
|
| [reply] |