1

Is there anyway to do something like this in perl (convert array hash and use it in one line)?

sub func{
 #from this
 my %args = @_;
 print $args{test};

 #to this
 print %{@_}{test};
}

Im using it for passing errors to callbacks like javascript use strict; use warnings;

sub error{
 my $msg = shift;
 print("ERROR: $msg\n");
}

sub parse_args{
    my %args = @_;
    return $args{args};
}

sub do_something{
   my $args = parse_args(
     args=>{@_},
     optional_args=>["fail_cb"]
   );
   if(!0){
    return(exists $args->{fail_cb} ? $args->{fail_cb}->(err=>"not good") : 0);
   }
}

do_something(
 fail_cb => sub{error(({@_})->{err});}
);

2 Answers 2

2

Yes, by making it into a reference and then dereferencing

sub func { say ${{@_}}{key} }

(I must ask, do you really want to be doing this?)

The {@_} creates a hash reference, while ${ ... }{} syntax dereferences it (item 2).


Update to the question edit

Apparently, the intent is to run a callback. But then you need to run that callback

sub func { ${{@_}}{key}->() }

func( key => sub { say "cb here" } );

If you were to print the value, as asked, you'd get the code-reference itself, CODE(0x...)

Or, pass the hashref with a key and (the reference of) arguments for the callback

my $hr = { k1 => sub { .. }, k2 => sub { .. }, .. };
...
func($hr, $key, $arrayref_cb_args);

sub func { $_[0]->{$_[1]}->(@{$_[2]}) }

where now func can decide dynamically what to run. This gives you far more flexibility in design.

For a ready test

perl -wE'
    sub tt { $_[0]->{$_[1]}->(@{$_[2]}) };
    tt( { k1 => sub { say "args: @_" }}, "k1", [qw(cb here)] )
'

prints the line   args: cb here

Sign up to request clarification or add additional context in comments.

7 Comments

Im using like javascript passes errors to callbacks. I will update question to explain.
the main part that I think is ugly is encapsulating the callback within an anonymouse subroutine but from what I can tell, I can't pass a subroutine reference with parameters as the callback ( fail_cb =>\&error(({@_})->{err}) ). This idea is that I can have a subroutine success(),exit(), etc.. that will display the message differently or I can define a completely new one as an anonymose subroutine and still have the err functionality.
The callback is still called within the do_something function in this case and the above code seems to work correctly as far as I can tell.
I think I understand the code (barely) but I am not sure how to apply it to what I'm trying to do. Would the subs defined in $_[0] be error, success, etc..? Also would it make more sense to define $_[0] hash outside tt so that it can be reused with multiple tt calls?
@TheAschr For example, if you have $rh = { error => sub { say "got error: @_" } }, then yes, func($hr, "error", $cb_args) will run sub { say "...: @_" } with whatever is in arrayref $cb_args. You can have a default for $cb_args refarray so that it's optional.
|
1

You can turn it into a hash reference easily with just

{@a}

and dereference entries with, for example

({@a})->{key}

Here's a debugger log:

$ perl -de0

Loading DB routines from perl5db.pl version 1.49_001
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(-e:1):   0
  DB<1> @a = ('a',1,'b',2,'c',3)

  DB<2> x @a
0  'a'
1  1
2  'b'
3  2
4  'c'
5  3
  DB<3> x {@a}
0  'a'
1  1
2  'b'
3  2
4  'c'
5  3
  DB<4> x ({@a})
0  HASH(0x804d82e0)
   'a' => 1
   'b' => 2
   'c' => 3
  DB<5> x ({@a})->{c}
0  3

1 Comment

The parens are not needed

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.