Method to add element to SetHash in Perl6 - hashmap

I'm just starting out with Perl6, and I'm trying to determine how to add an element to a SetHash. It seems that hash notation works, but I'm wondering if I'm missing a method that does the same thing? I'm looking at the SetHash documentation, but I find it a bit opaque.
my $foo = SetHash.new();
$foo{'a'} = True;
'a' ∈ $foo # True;

This is a bug, though what exact method SetHash should have is still up for debate. https://rt.perl.org/Public/Bug/Display.html?id=128903.
Someone else posted this as an answer, but it seems to have been deleted.

This seems to work now:
my $hash = SetHash.new();
$hash{'a'} = True;
say $hash, " in a ", $hash.^name;
Returns: SetHash(a) in a SetHash. So you're good to go here. The documentation might be improved, anyway. We'll do just that.

Related

Converting match object to string in perl6

I was trying to convert a match object to a string in perl6. The method Str on a match object is defined as:
method Str(Match:D: --> Str:D)
I would think I could use Str($match) to accomplish this. And it seems to convert it to a string, but I'm getting an error using the string with the following code:
my $searchme = "rudolph";
my $match = $searchme ~~ /.*dol.*/;
say $match.WHAT;
my $test1 = Str($match);
say $test1.WHAT;
say $test1;
With the output:
(Match)
(Str)
With the error:
Cannot find method 'gist': no method cache and no .^find_method in
block at .code.tio line 6
However, if I run:
my $searchme = "rudolph";
my $match = $searchme ~~ /.*dol.*/;
say $match.WHAT;
my $test1 = $match.Str;
say $test1.WHAT;
say $test1;
I get no error and the result:
(Match)
(Str)
rudolph
Is this a bug or me misunderstanding how it works?
Thanks for reading.
I'm writing this up as an answer even though it's actually an incomplete discussion of a bug, so not at all normal SO fare. The alternative of lots of comments doesn't seem better.
It's a bug. Perhaps you just golfed this.
dd $test1; instead of say $test1; is helpful in that it displays BOOTStr $test1 = (BOOTStr without .perl method).
Based on that I searched the rakudo repo for BOOTStr and that led to the above issue.
Golfing it further leads to:
say $ = Str(Match.new);
Note that these are all fine:
say Str(Match.new);
say $ = Int(Match.new);
say $ = Str(Date.new: '2015-12-31');
It appears to be a combination of leaking some implementation details regarding how Rakudo/NQP/MoarVM bootstrap; Match being an NQP object; Str() on that being wonky; and assigning it to a Scalar container (the $ is an anonymous one) making that wonkiness visible.
I'll add more when/if I figure it out.

How to skip a Parameter with Default Values in Groovy?

My Groovy method has 3 parameters and the last 2 have default values. I want to skip the second parameter, and only provide values for the first and the third like so..
def askForADate(girlsName, msg = 'Will you go out with me?', beg = 'pretty please!!') {
println "$girlsName, $msg $beg!"
}
askForADate('Jennifer',,'Because I love you!')
Right now this prints out...
Jennifer, Because I love you! pretty please!!!
So it looks like it is plugging the value I am passing in for the third parameter into the second.
How to fix that?
As doelleri said, you'll need to write two version of thie method.
Unless you'll use some groovy goodness with named arguments!
def askForADate(Map op, girlsName) {
println "$girlsName, ${op.get('msg', 'Will you go out with me?')} ${op.get('beg', 'pretty please!!')}!"
}
askForADate(beg: 'Because I love you!', 'Jennifer')
Prints out: Jennifer, Will you go out with me? Because I love you!!
See http://mrhaki.blogspot.com/2015/09/groovy-goodness-turn-method-parameters.html for more details
This solution has the clear disadvantage of reordering the arguments as now the girls name is last in line.

How can I reference an unnamed argument of a when expression?

I have a when expression that looks something like this:
when(foo.toString()){
"" ->'A'
"HELLO" ->'B'
"GOODBYE"->'C'
else ->foo.toString()[0]//problematic method call duplication
}
Now, I don't want to call foo.toString() twice, but I also want this to remain a single expression. Is there a convenient way for me to access the value I passed into the when expression in its else block, such as the it or this# syntax found elsewhere in the language?
I'm currently using the following work-around:
with(foo.toString()){
when(this){
"" ->'A'
"HELLO" ->'B'
"GOODBYE"->'C'
else ->this[0]
}
}
But this introduces another block, and is less readable than I'd like. Is there a better solution?
For the when block there's no variable specified, but you can use the let() function for a similar behavior which might be a little better than your workaround, but behaving the same.
foo.toString().let{
when(it){
"" ->'A'
"HELLO" ->'B'
"GOODBYE"->'C'
else ->it[0]
}
}

What's the best way to extract a single value from a Set in groovy?

If I have a Set that I know contains a single element, what's the best way to extract it? The best I can come up with is this, but it doesn't feel very groovy:
set = [1] as Set
e = set.toList()[0]
assert e == 1
If I'm dealing with a list, I've got lots of nice ways to get the element, none of which seem to work with Sets:
def list = [1]
e = list[0]
(e) = list
e = list.head()
One other possibility (which will work in Java or Groovy):
set.iterator().next()
A few alternatives, none of them very pretty:
set.iterator()[0]
set.find { true }
set.collect { it }[0]
Finally, if it's guaranteed that that set has only one item:
def e
set.each { e = it }
The underlying issue, of course, is that Java Sets provide no defined order (as mentioned in the Javadoc), and hence no ability to get the nth element (discussed in this question and this one). Hence, any solution is always to somehow convert the set to a list.
My guess is that either of the first two options involve the least data-copying, as they needn't construct a complete list of the set, but for a one-element set, that should hardly be a concern.
Since Java 8, here is another solution that will work for both Java and Groovy:
set.stream().findFirst().get()
Even when this question is quite old, I am sharing my just a bit prettier solution.
(set as List).first()
(set as List)[0]
If you need to take null into account (not the case in this question):
(set as List)?.first()
(set as List)?.get(index)
Hope it helps! :)

preg_replace: reference object in replacement

Do you know of any way to reference an object in the replacement part of preg_replace. I'm trying to replace placeholders (delimited with precentage signs) in a string with the values of attributes of an object. This will be executed in the object itself, so I tried all kinds of ways to refer to $this with the /e modifier. Something like this:
/* for instance, I'm trying to replace
* %firstName% with $this->firstName
* %lastName% with $this->lastName
* etc..
*/
$result = preg_replace( '~(%(.*?)%)~e', "${'this}->{'\\2'}", $template );
I can't get any variation on this theme to work. One of the messages I've been getting is: Can't convert object Model_User to string.
But of course, it's not my intention to convert the object represented by $this to a string... I want to grab the attribute of the object that matches the placeholder (without the percentage signs of course).
I think I'm on the right track with the /e modifier. But not entirely sure about this either. Maybe this can be achieved much more simple?
Any ideas about this? Thank you in advance.
Like I commented to Paul's answer: in the meanwhile I found the solution myself. The solution is much more simple than I thought. I shouldn't have used double quotes.
The solution is as simple as this:
$result = preg_replace( '~(%(.*?)%)~e', '$this->\\2', $template );
Hope this helps anyone else for future reference.
Cheers.
Check out preg_replace_callback - here's how you might use it.
class YourObject
{
...
//add a method like this to your class to act as a callback
//for preg_replace_callback...
function doReplace($matches)
{
return $this->{$matches[2]};
}
}
//here's how you might use it
$result = preg_replace_callback(
'~(%(.*?)%)~e',
array($yourObj, "doReplace"),
$template);
Alternatively, using the /e modifier, you could maybe try this. I think the only way to make it work for your case would be to put your object into global scope
$GLOBALS['yourObj']=$this;
$result = preg_replace( '~(%(.*?)%)~e', "\$GLOBALS['yourObj']->\\2", $template );

Resources