1

I have the following in the perl code:

$art_entities->{$rel_art_path}++;

I see that it is a post increment on a hash, how does it work? What would be something similar in Java or C#?

ikegami
  • 367,544
  • 15
  • 269
  • 518
Harvey Lin
  • 724
  • 11
  • 25

3 Answers3

4

The ++ operator returns the value and then increments the variable by one. Hashes are just unordered collections of scalar values indexed by their associated string key; incrementing a scalar in a hash is no different from incrementing a scalar outside of a hash.

The following are functionally equivalent:

$hash{foo}++;
$hash_ref->{foo}++;
$foo++;

There's a little extra magic built in to Perl's auto-increment operator, though:

If you increment a variable that is numeric, or that has ever been used in a numeric context, you get a normal increment. If, however, the variable has been used in only string contexts since it was set, and has a value that is not the empty string and matches the pattern /^[a-zA-Z]*[0-9]*\z/, the increment is done as a string, preserving each character within its range, with carry:

print ++($foo = "99");    # prints "100"
print ++($foo = "a0");    # prints "a1"
print ++($foo = "Az");    # prints "Ba"
print ++($foo = "zz");    # prints "aaa" 

undef is always treated as numeric, and in particular is changed to 0 before incrementing (so that a post-increment of an undef value will return 0 rather than undef).

Java and C# both have increment operators, but as far as I know, they're not nearly as magical as Perl's. Java's HashMap provides get() and put() methods, so you don't get direct access to the underlying data:

map.put(key, map.get(key) + 1);

C# collections use square brackets, so if you had a Dictionary, for example:

dict["foo"]++;
Matt Jacob
  • 6,503
  • 2
  • 24
  • 27
  • According to the docs, both `map.get(key) + 1` and `dict["foo"]` will fail if the element doesn't already exists, which is almost always the case when `++` is used. – ikegami Mar 28 '17 at 18:42
4

It creates an element in the hash if it doesn't exist, then increments its value by one[1].

For example,

my %counts;
++$counts{$_} for split(//, 'abracadabra');

produces

my %counts = (
   a => 5,
   b => 2,
   c => 1,
   d => 1,
   r => 2,
);

It's also useful for filtering out duplicates. For example,

my %seen;
my @uniq = grep !$seen{$_}++, split(//, 'abracadabra');

produces

my @uniq = qw( a b r c d );

Perl:

my %dict;

++$dict{$key};   # $dict{$key}++ in scalar context gets optimized into ++$dict{$key}.

C#:

Dictionary<string, int> dict = new Dictionary<string, int>();

int i;
dict.TryGetValue(key, out i);
dict[key] = i+1;

C#:

Dictionary<string, int> dict = new Dictionary<string, int>();

if (dict.ContainsKey(key))
   ++dict[key];
else
   dict[key] = 1;

Java:

Map<String, Integer> dict = new HashMap<String, Integer>();

Integer i = dict.get(key);
if (i == null) {
   map.put(key, 1);
} else {
   map.put(key, i+1);
}

  1. ++ has some "magical" behaviour if the variable being incremented contains a string (incrementing a into b, for example), but I don't think that's relevant here.
ikegami
  • 367,544
  • 15
  • 269
  • 518
-1
$art_entities->{$rel_art_path}++;

$art_entities is a variable (a scalar, see the leading $ sign). With the arrow syntax, it looks like it is an object.

$rel_art_path is another scalar variable.

->{...} accesses a field (right side of the arrow, in {curly braces}) from the object on the left side of the arrow. Perl does not do much in terms of access limitations, i.e., there is no public, private, or protected. You could add your own code to enforce private access (see Perl Best Practices) or use a class framework like Moose.

The code uses the value of $rel_art_path as a field name in the $art_entities object.

In Java, this would be done with reflection:

import java.lang.reflect.Field;

public class SomeClass {
    public static void main(String[] args) throws Exception {
        SomeOtherClass soc = new SomeOtherClass();
        doSomething(soc, "someValue");
        soc.print();
    }

    public static void doSomething(Object art_entities, String rel_art_path)
    throws Exception {
        Class<?> c = art_entities.getClass();
        Field field = c.getDeclaredField(rel_art_path);
        field.setInt(art_entities, field.getInt(art_entities) + 1);
    }
}

class SomeOtherClass {
    public int someValue = 0;

    public void print() {
        System.out.println("my value is " + someValue);
    }
}

(I've used your variable names in the Java code to make it clearer which corresponds to which. Obviously they are Perl style (using underscores), not Java (camel case).)

In Java, this is hackish and quite a lot to write, in Perl it's short and normal.

Robert
  • 7,394
  • 40
  • 45
  • 64
  • 1
    `$art_entities` is a hash reference. It *could* be an object, but there's nothing in the OP's code to suggest that. I imagine the closest equivalent in Java would be fetching a value from a hashmap or the equivalent data structure, incrementing it, and storing the result. – ThisSuitIsBlackNot Mar 28 '17 at 16:55
  • $art_entities is a result from $self->{_art_entities}, does that clarify things? – Harvey Lin Mar 28 '17 at 17:32
  • @HarveyLin There you have the same thing: `$self` is what Perl programmers often use for `this` in Java, even though it's not a keyword in Perl. `$self->{_art_entities}` refers to the member variable `_art_entities` of whatever object `$self` is. `_art_entities` does not start with a `$`, so there is no indirection, and you'd have this as normal member access in Java (e.g., "soc.someValue" in my example code), without need for reflection. – Robert Mar 28 '17 at 17:49
  • And this is how art_entities gets passed to $self: my %art_entities; $self->{_art_entities} = \%art_entities; – Harvey Lin Mar 28 '17 at 17:53