in reply to Does Go steal from Perl? :-)

Autovivification in Perl happens when you try to dereference an undefined value as an arrayref or hashref. A new array or hash is silently created and the undefined value is changed to be a reference to that array or hash.

There's no autovivification going on in the example you gave. There's only one hash used (though Go calls them maps, not hashes), and it's explicitly declared in the first line of the function.

The counts[input.Text()]++ part relies on:

Replies are listed 'Best First'.
Re^2: Does Go steal from Perl? :-)
by kikuchiyo (Hermit) on Aug 03, 2018 at 20:05 UTC

    There are some dangerous misconceptions in this analysis.

    Go is a strongly and explicitly typed language. There is no such thing as an undefined value and there is certainly no such thing as a numeric context. Instead, every variable has a well-defined, fixed type, specified (or inferred) when the variable is declared, and every type has a well-defined zero value, that is, any variable not explicitly assigned to will be initialized to the zero value of its type.

    Let's look at the first line then:

    • It declares a map, specifying explicitly that the keys are strings (which is a separate, pre-defined type in Go) and the values are integers. Using anything else than strings as keys or treating the values as anything other than integers would result in a compile time error.
    • It initializes the map, allocating the necessary internal data structures and returning the result. The zero value of any map type is such an empty, ready-to-use map.
    • It assigns this empty, initialized map to counts, using the := operator which declares a variable using type inference. The compiler knows that counts has to be a map[string]int, so you don't have to write it twice.

    In turn, the counts[input.Text()]++ line can be analyzed as follows:

    • Attempting to read the value for a key that does not have an entry in the map will result in the zero value of the value type, in this case 0. Not because there is any kind of numeric context anywhere, but because the map's value type is integer.
    • Elements can be added to the map with assignment operations.
    • x++ is not an expression in Go, and you can't use it as such; it is a statement that can be thought as the atomic equivalent of x=x+1, and as such, it is an assigment.

    It is likely that the authors of go recognized the code in question as a common idiom and wrote the language standard with it in mind, but the details explained above make it clear that the underlying concepts are rather different from those of Perl.

      There is no such thing as an undefined value and there is certainly no such thing as a numeric context

      Actually, even strongly typed languages have a numeric context - and other contexts. In strongly typed languages like Go, the context is used (at compile time) to enforce that a variable or value of a specific type is used.

      Also, being strongly typed does not automatically exclude the concept of "undefined value". "undefined" is a sentinel that is reserved and predefined by the language. Many "purists" mistakenly equate undefined with uninitialized. While uninitialized implies undefined, the reverse need not be true. Like "NaN" (not a number) is useful, having undefined as a reserved, predefined representation of a sentinel can also be useful. Otherwise, you have to decide on a value to use as a sentinel, then hope that value never appears in your data.*

      Unfortunately, the way Perl uses undefined contributes to the confusion between uninitialized and undefined. It would have been better for Perl to have a flag for uninitialized as well as undefined. At least Perl has a test for undefined. Off hand, I don't recall any other languages that provide a test for undefined.

      ---

      * While NaN could be used as a sentinel, it's mathematical definition is an unrepresentable value, which is different from an undefined value.