Re: Hash

Yes, Hash has definitely special features,
but - as mentioned in the first post - this behaviour is not as someone
would expect...

h=Hash.new ; h[1] << 'x' ; h[2] <<'y'; h # very special, very amazing

No, this behaviour is *exactly* as someone would expect when assigning an
*object* as a default value, which arrays or hashes certainly are.

-a

···

On Mon, Jun 6, 2022 at 1:43 PM Die Optimisten <inform@die-optimisten.net> wrote:

Yes, Hash has definitely special features,
but - as mentioned in the first post - this behaviour is not as someone
would expect...

h=Hash.new ; h[1] << 'x' ; h[2] <<'y'; h # very special, very amazing

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/http://twitter.com/halostatue

Hi
The same as a=Array.new { }; a[1] << 1 # default value, but
doesn't work - also very special...
So - you see what I mean - a beginner will not understand why h[1]<<'x'
doesn't affect h[1] ...
Opti

···

Am 06.06.22 um 19:44 schrieb Austin Ziegler:

No, this behaviour is *exactly* as someone would expect when assigning
an *object* as a default value, which arrays or hashes certainly are.

-a

On Mon, Jun 6, 2022 at 1:43 PM Die Optimisten > <inform@die-optimisten.net <mailto:inform@die-optimisten.net>> wrote:

    Yes, Hash has definitely special features,
    but - as mentioned in the first post - this behaviour is not as
    someone
    would expect...

    h=Hash.new ; h[1] << 'x' ; h[2] <<'y'; h # very special, very
    amazing

    Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org
    <mailto:ruby-talk-request@ruby-lang.org>?subject=unsubscribe>
    <ruby-talk list: member options login page>

--
Austin Ziegler • halostatue@gmail.com <mailto:halostatue@gmail.com> •
austin@halostatue.ca <mailto:austin@halostatue.ca>
http://www.halostatue.ca/http://twitter.com/halostatue

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

No, that’s not the same as, and your obtuseness on this matter has been
corrected multiple times.

Providing a block does something different than providing a fixed object, *and
this is documented*.

Hash.new

(from ruby core)

···

------------------------------------------------------------------------
  Hash.new(default_value = nil) -> new_hash
  Hash.new {|hash, key| ... } -> new_hash

------------------------------------------------------------------------

Returns a new empty Hash object.

The initial default value and initial default proc for the new hash
depend on which form above was used. See {Default
Values}[#class-Hash-label-Default+Values].

If neither an argument nor a block given, initializes both the default
value and the default proc to nil:
  h = Hash.new
  h.default # => nil
  h.default_proc # => nil

If argument default_value given but no block given, initializes
the default value to the given default_value and the default proc
to nil:
  h = Hash.new(false)
  h.default # => false
  h.default_proc # => nil

If a block given but no argument, stores the block as the default proc
and sets the default value to nil:
  h = Hash.new {|hash, key| "Default value for #{key}" }
  h.default # => nil
  h.default_proc.class # => Proc
  h[:nosuch] # => "Default value for nosuch"

Initializing with a block is different than initializing with a value.

-a

On Mon, Jun 6, 2022 at 1:50 PM Die Optimisten <inform@die-optimisten.net> wrote:

Hi
The same as a=Array.new { }; a[1] << 1 # default value, but doesn't
work - also very special...
So - you see what I mean - a beginner will not understand why h[1]<<'x'
doesn't affect h[1] ...
Opti

Am 06.06.22 um 19:44 schrieb Austin Ziegler:

No, this behaviour is *exactly* as someone would expect when assigning an
*object* as a default value, which arrays or hashes certainly are.

-a

On Mon, Jun 6, 2022 at 1:43 PM Die Optimisten <inform@die-optimisten.net> > wrote:

Yes, Hash has definitely special features,
but - as mentioned in the first post - this behaviour is not as someone
would expect...

h=Hash.new ; h[1] << 'x' ; h[2] <<'y'; h # very special, very amazing

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/http://twitter.com/halostatue

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe> <ruby-talk-request@ruby-lang.org?subject=unsubscribe><ruby-talk list: member options login page> <ruby-talk list: member options login page>

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/http://twitter.com/halostatue

Exactly! I think the confusion (maybe) comes from (wrongly) expecting these two to be the same:
h = Hash
h = Hash.new

The fact that Ruby lets you omit the parentheses makes it more troublesome. I think people would behave differently if you _had_ to do:
h = Hash.new() # eh, why are we passing an array to it, hmm!?

In any case, this is what it is - and if you read the docs, it's clear.
If you don't read it, you will be surprised the first couple of times and then you'll learn it :slight_smile:

Now that this thread has continued, I'd like to promote the post that come out of this discussion.

I learnt a few things.

Best wishes,
Mohit.

···

On 2022-6-7 1:53 am, Austin Ziegler wrote:

No, that’s not the same as, and your obtuseness on this matter has been corrected multiple times.

Providing a block does something different than providing a fixed object, *and this is documented*.

Hash.new

Hi
You didn't get the context (and - speaking of obtuseness),
it's about the need of strange syntax / constructs: nobody will know by
thinking logically how to get the wanted things, which we have for
Hashes and Arrays, like
(for example): a=Array.new { }; a[1] << 1 # which is NOT working
[at all], what is confusing (thinking similar to using a hash...)
Maybe now you understand, that I'm speaking of other things than value
or proc, I'm speaking of how to reach that purpose.
Opti

···

Am 06.06.22 um 19:53 schrieb Austin Ziegler:

No, that’s not the same as, and your obtuseness on this matter has
been corrected multiple times.

Providing a block does something different than providing a fixed
object, *and this is documented*.

“A foolish consistency is the hobgoblin of little minds, adored by little
statesmen and philosophers and divines. With consistency a great soul has
simply nothing to do. He may as well concern himself with his shadow on the
wall. Speak what you think now in hard words, and tomorrow speak what
tomorrow thinks in hard words again, though it contradict every thing you
said today. — 'Ah, so you shall be sure to be misunderstood.' — Is it so
bad, then, to be misunderstood? Pythagoras was misunderstood, and Socrates,
and Jesus, and Luther, and Copernicus, and Galileo, and Newton, and every
pure and wise spirit that ever took flesh. To be great is to be
misunderstood.”
― Ralph Waldo Emerson, Self-Reliance
<Self-Reliance Quotes by Ralph Waldo Emerson>

*Most* people do not construct hashes or arrays in Ruby with Hash.new or
Array.new. They use {} and literals. If they need something else, they
are encouraged to read the documentation. Which, if you’d done, you would
see that Array.new *does* have a block form, but it is associated with a
*size* parameter, because there is no meaningful "default_proc" concept on
Array.

That is:

a = Array.new(3, )
a[0] << 3
p a # => [[3], [3], [3]]

But:

a = Array.new(3) {}
a[0] << 3
p a # => [[3], , ]

It works *exactly* the way that one would expect it to given that the
documentation says:

With no block and arguments size and default_value, returns an Array of the

given size; each element is that same default_value:

Unless, of course, one is Die Optimisten or obtuse.

Please stop deliberately obfuscating what are clear, well-documented, and
well-explained phenomena because you refuse to accept that they are natural
and correct behaviours.

-a

···

On Tue, Jun 7, 2022 at 10:01 AM Die Optimisten <inform@die-optimisten.net> wrote:

Hi
You didn't get the context (and - speaking of obtuseness),
it's about the need of strange syntax / constructs: nobody will know by
thinking logically how to get the wanted things, which we have for Hashes
and Arrays, like
(for example): a=Array.new { }; a[1] << 1 # which is NOT working [at
all], what is confusing (thinking similar to using a hash...)
Maybe now you understand, that I'm speaking of other things than value or
proc, I'm speaking of how to reach that purpose.
Opti

Am 06.06.22 um 19:53 schrieb Austin Ziegler:

No, that’s not the same as, and your obtuseness on this matter has been
corrected multiple times.

Providing a block does something different than providing a fixed object, *and
this is documented*.

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/http://twitter.com/halostatue

As I understand, the main issue here is that Die Optimisten may not understand a concept of "passing an object by reference" compared to "passing by copy".

Ruby is consistent with regards to that. Objects are passed by reference and everything is an object, but some objects are immutable (those objects are internally passed by copy, but this is transparent, as they are immutable: Symbols, Integers, Floats on some architectures, booleans and nil), The immutable objects don't have methods that have side effects that modify them (because it's impossible), but mutable objects don't share that characteristic. Most often they end with "!", which is obvious, but same goes for "<<" and "=", though arrays also have other set of methods with side effects: #push, #pop, #shift, #unshift.

Die Optimisten may have came from the PHP environment, where, well, objects (since PHP 5, in PHP 4 times people used to write "$a = &new MyClass();") are passed by reference, but the array-and-hash-hybrid-called-an-array is not an object. Therefore it's passed by copy (unless you infect it with "&"). So, for instance:

php > $a = [1];
php > $b = $a;
php > $a[0] = 2;
php > var_export($a);
array (
0 => 2,
)
php > var_export($b);
array (
0 => 1,
)
php >

Now, back to the main example:

[6] pry(main)> h = Hash.new(0)
=> {}
[7] pry(main)> h[0] += 1
=> 1
[8] pry(main)> h[:a] += 2
=> 1
[9] pry(main)> h[true] += 3
=> 1
[10] pry(main)> h
=> {0=>1, :a=>2, true=>3}
[11] pry(main)>

Compared to:

[11] pry(main)> h = Hash.new()
=> {}
[12] pry(main)> h[0] << 1
=> [1]
[13] pry(main)> h[:a] << 2
=> [1, 2]
[14] pry(main)> h[true] << 3
=> [1, 2, 3]
[15] pry(main)> h
=> {}
[16] pry(main)>

This is surprising if you don't know that the << method has side effects that effected an array, but didn't modify the hash. But it's possible to use other method, that doesn't have side effects and the semantics are the same as for the Integer example:

[16] pry(main)> h = Hash.new()
=> {}
[17] pry(main)> h[0] += [1]
=> [1]
[18] pry(main)> h[:a] += [2]
=> [2]
[19] pry(main)> h[true] += [3]
=> [3]
[20] pry(main)> h
=> {0=>[1], :a=>[2], true=>[3]}
[21] pry(main)>

The main difference is that we both: don't modify the original object and we call = method on Hash. Let's try another example:

[21] pry(main)> a =
=>
[22] pry(main)> b = [a,a,a]
=> [, , ]
[23] pry(main)> a << 5
=> [5]
[24] pry(main)> b
=> [[5], [5], [5]]
[25] pry(main)> b[1] += [6]
=> [5, 6]
[26] pry(main)> b
=> [[5], [5, 6], [5]]
[27] pry(main)> a << 0
=> [5, 0]
[28] pry(main)> b
=> [[5, 0], [5, 6], [5, 0]]
[29] pry(main)>

As we see, `b[1] += [6]` was expanded to `b[1] = b[1] + [6]` which was further expanded to `b.=(1, b[1] + [6])`. In this whole example, this is the only line that modified the `b` array, because we called a method (=) with side effects to the `b` array.

To try to explain this behavior better - think of it in terms of C. What we carry is not actually an object, but a pointer to an object. So it's not an array of objects actually, but array of pointers to objects. So in the Pry session line 24 of the previous example, we had an array of three pointers, all three pointing to the same Array object. Line 25 modified the `b` array, to change the second pointer, to point to a new object: an array that is a concatenation of arrays [5] and [6] (and this is basically how Ruby works internally).

The choice of "passing by reference" everywhere in Ruby is good for three reasons:

- it's consistent
- it's performant (no need to spend precious CPU cycles on copying perhaps large structures)
- it's powerful, because it allows us to express data structures like cyclic graphs. If Ruby chose passing by copy everywhere, it would require from implementer creating a complex level of abstraction.

As I understand, the main issue here is that Die Optimisten may not

understand a concept of "passing an object by reference" compared to
"passing by copy".

The way I see it, Ruby only has "pass by value" semantics. Like Java and
others.

Whether an object is mutable via its API does not matter. Neither does
internal optimizations.

Perl is truly pass-by-reference:

    % perl -wle '$x = 0; sub { ++$_[0] }->($x); print $x'
    1

See? The contents of the *variable* in the caller have been changed. That
is, the array of function arguments (@_) points to the same memory
locations of the caller. In Perl you can implement a swap function that
swaps the arguments in the caller.

···

On Tue, Jun 7, 2022 at 11:02 PM hmdne <hmdne@airmail.cc> wrote:

I’ve always called Ruby’s semantics "pass reference by value". "Pass by
value" implies that there’s a lot of object copying going on.

It makes it clearer that you’re *always* passing an object *reference*, but
you’re passing that reference by value, which means you can’t do the
argument swap the way that Perl can.

-a

···

On Tue, Jun 7, 2022 at 6:04 PM Xavier Noria <fxn@hashref.com> wrote:

On Tue, Jun 7, 2022 at 11:02 PM hmdne <hmdne@airmail.cc> wrote:

As I understand, the main issue here is that Die Optimisten may not

understand a concept of "passing an object by reference" compared to
"passing by copy".

The way I see it, Ruby only has "pass by value" semantics. Like Java and
others.

--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/http://twitter.com/halostatue

You’ve provided an excellent description.

Unfortunately, Die O. has been provided this sort of description in the
past with as much detail as you’ve given with as much impact on their
understanding. The problem at this point is not a lack of information and
understanding, it is a deliberate obtuseness inherent in their combative
style. They have, so far, refused to acknowledge that they are holding onto
a misunderstanding and have instead decided that it is Ruby *itself* that
is wrong.

Hopefully someone will benefit from your explanation (I’d quibble and say
"pass (object) reference by value" rather than just "pass by reference";
it’s a subtle and important distinction). If experience is any guide, Die
O. will not be that person, deliberately so.

-a

···

On Tue, Jun 7, 2022 at 5:02 PM hmdne <hmdne@airmail.cc> wrote:

As I understand, the main issue here is that Die Optimisten may not
understand a concept of "passing an object by reference" compared to
"passing by copy".

--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/http://twitter.com/halostatue

Point is, in Ruby and in Java, your explicit data model is the reference.
You pass references around by value (there are two distinct storages for
the same value).

Agreed. As I said, I consider my clarification mostly a quibble.
Pass-by-reference is *certainly* enough for most people to get the
distinction.

···

On Tue, Jun 7, 2022 at 6:16 PM Xavier Noria <fxn@hashref.com> wrote:

Point is, in Ruby and in Java, your explicit data model is the reference.
You pass references around by value (there are two distinct storages for
the same value).

--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/http://twitter.com/halostatue

Can we, I don’t know, stop being assholes to each other? The name calling
isn’t contributing anything productive to the thread.

···

On Tue, Jun 7, 2022 at 5:18 PM Austin Ziegler <halostatue@gmail.com> wrote:

On Tue, Jun 7, 2022 at 6:16 PM Xavier Noria <fxn@hashref.com> wrote:

Point is, in Ruby and in Java, your explicit data model is the reference.
You pass references around by value (there are two distinct storages for
the same value).

Agreed. As I said, I consider my clarification mostly a quibble.
Pass-by-reference is *certainly* enough for most people to get the
distinction.

--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/http://twitter.com/halostatue

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

--

* Amir Rajan
** PS
I welcome VSRE emails. Learn more at http://vsre.info/.
** PPS
I reply to every legitimate email I get. So, if you don't hear from me
within a week. Email me again since there's a high chance that the email
got lost in my inbox.

The problem in this topic is that "reference" as used by Ruby, Java, or
Python terminology, and "reference" in "pass-by-reference" are different
words. The former means "handler", and the latter means "storage alias".

C, which is also pass-by-value only, makes this apparent: If you pass a
pointer to a function, the function can change the value it points to, and
that is seen by the caller. What you cannot change is the memory location,
the pointer itself, in the caller. That integer is what you really passed,
by value. (Austin, you know this, writing for people reading the thread.)

Hello, Ziegler,
> Unless, of course, one is Die Optimisten or obtuse.
PLEASE omit insulting!
Also YOU began using obtuseness.

As I wrote, it's about the (strange - not coherent/consistent) "syntax"
you have to use to get what you want. I pointed out, that for Array it
is again another form.
Yes, if reading (and remembering) all the documentation (with all its
"exceptions"), than it works "as expected" (as documented, although many
things are not documented!).
It would be a philosophical discussion if these are "natural and correct
behaviours." - Can a programming language be "natural"? - What is
"correct" behaviour ?

No, I'm coming from C (thanks hdme, but I know that) - yes, also
surprising.
But (very) surprising for me is that h=Hash.new(); h[1] << 1 # we
should at least get a warning if changing the defaultval; nobody
expects after changing h[1], that (the key) h[1] does not exist,
although it's clear when understanding what is done.
NOT natural, NOT obvious, therefore I say: "not correct":
Shouldn't have Hash.new... for one and for uniq defaults allow _being
used in the same way_ (if someone doesn't know which case is used) -- it
is error-prone and "not correct" that changing h[1] changes the
default-val. - That's the message, maybe Ziegler now judge about
obtuseness...

> If experience is any guide, Die O. will not be that person,
deliberately so.
Very comfortable... Shouldn't we ban you?!? - YOU're the offensive person!
Maybe others look over the egde of the plate (never you!)
- BECAUSE of experience, my conclusion is that it's Ruby which should be
adapted...

a = Array.new(3) {}

Yes, AND Hash.new { } # (analogous to Array.new ... ) => does
nothing ...

Opti

···

Unless, of course, one is Die Optimisten or obtuse.

Please stop deliberately obfuscating what are clear, well-documented,
and well-explained phenomena because you refuse to accept that they
are natural and correct behaviours.

-a

Die, if you come from C, the mental model to understand how Ruby works is
that *everything is pointers to structs*. You never hold a struct value,
you are always dealing with pointers managed by the VM on your behalf.

So, you assign pointers, you pass pointers to methods, and accessing the
struct by deferencing (the dot acts as ->) changes the target struct in
memory, so everyone holding the same pointer of course sees the new value
no matter where that happened.

As I wrote, it's about the (strange - not coherent/consistent) "syntax"
you have to use to get what you want. I pointed out, that for Array it
is again another form.

Just stop. You have been trolling this mailing list for years, convinced
that your view is the only correct view of Ruby and refusing to accept any
mental model except your own. If, indeed, you actually know C, then you
know that there’s places in C syntax where consistency simply doesn’t
exist, as is the case with *any* programming language. Each and every
instance of UB is a lack of consistency and clarity where one is invited to
mess around and find out what your compiler does, because every compiler
will do it differently.

In comparison, Ruby object instantiation is crystal clear *and*
well-documented. Just because you can’t accept that the semantics are
foreign *to you* does not make them surprising, unobvious, or anything
except "foreign to you".

Let’s try to provide some education to readers of the thread, even though
it will obviously not be you.

But (very) surprising for me is that h=Hash.new(); h[1] << 1 # we
should at least get a warning if changing the defaultval; nobody
expects after changing h[1], that (the key) h[1] does not exist,
although it's clear when understanding what is done.

Variables in Ruby are not locations. They are labels. In C, the expression
`uint32_t a = b = 3` takes up approximately 8 bytes of stack memory. In
Ruby, the expression `a = b = 3` takes up approximately one Object of
memory (certain numbers are special in most implementations of Ruby, but
that is an implementation detail about most numbers being "internalized").

Variables in Ruby are labels to *references* (to objects). Expressions in
Ruby return *references* (to objects). With this minimal information, it
becomes pretty easy to reason that `h = Hash.new()` gives me a reference
to the Hash which I have labeled `h`. If I don’t understand why `h[1] << 1`
modifies `h.default`, then I read some documentation and realize that even
if I do `h[1]`, that does not necessarily mean `h.has_key?(1)` returns true
because I provided a mutable default object. Or I could even see
`h[1].object_id == h[2].object_id` returning a true value, and
enlightenment might actually occur.

I might actually then be able to reason that `h[1] == h.default` because
I’m really dealing with object references all the way down so that when I
modify `h[1]` because `h.has_key?(1) == false`, I’m really modifying
`h.default`. This isn’t something that would occur to a C genius, of
course, because reading the fine manual would disabuse said genius of their
ability to troll people on the same or similar topics again, and again, and
again.

-a

···

--
Austin Ziegler • halostatue@gmail.com • austin@halostatue.ca
http://www.halostatue.ca/http://twitter.com/halostatue

Hello Ziegler,
I wrote my prev mail only because of your (many, and offending!) answers.
- Seems you didn't get it by now... Read the first mail again
(4.6.2022), and then decide if it is possible that I already knew all
what you described thereafter?
Opti

···

Am 08.06.22 um 16:59 schrieb Austin Ziegler:

    As I wrote, it's about the (strange - not coherent/consistent)
    "syntax"
    you have to use to get what you want. I pointed out, that for Array it
    is again another form.

Just stop. You have been trolling this mailing list for years,
convinced that your view is the only correct view of Ruby and refusing
to accept any mental model except your own. If, indeed, you actually
know C, then you know that there’s places in C syntax where
consistency simply doesn’t exist, as is the case with *any*
programming language. Each and every instance of UB is a lack of
consistency and clarity where one is invited to mess around and find
out what your compiler does, because every compiler will do it
differently.

In comparison, Ruby object instantiation is crystal clear *and*
well-documented. Just because you can’t accept that the semantics are
foreign *to you* does not make them surprising, unobvious, or anything
except "foreign to you".

Let’s try to provide some education to readers of the thread, even
though it will obviously not be you.

    But (very) surprising for me is that h=Hash.new(); h[1] << 1 # we
    should at least get a warning if changing the defaultval; nobody
    expects after changing h[1], that (the key) h[1] does not exist,
    although it's clear when understanding what is done.

Variables in Ruby are not locations. They are labels. In C, the
expression `uint32_t a = b = 3` takes up approximately 8 bytes of
stack memory. In Ruby, the expression `a = b = 3` takes up
approximately one Object of memory (certain numbers are special in
most implementations of Ruby, but that is an implementation detail
about most numbers being "internalized").

Variables in Ruby are labels to *references* (to objects). Expressions
in Ruby return *references* (to objects). With this minimal
information, it becomes pretty easy to reason that `h = Hash.new()`
gives me a reference to the Hash which I have labeled `h`. If I don’t
understand why `h[1] << 1` modifies `h.default`, then I read some
documentation and realize that even if I do `h[1]`, that does not
necessarily mean `h.has_key?(1)` returns true because I provided a
mutable default object. Or I could even see `h[1].object_id ==
h[2].object_id` returning a true value, and enlightenment might
actually occur.

I might actually then be able to reason that `h[1] == h.default`
because I’m really dealing with object references all the way down so
that when I modify `h[1]` because `h.has_key?(1) == false`, I’m really
modifying `h.default`. This isn’t something that would occur to a C
genius, of course, because reading the fine manual would disabuse said
genius of their ability to troll people on the same or similar topics
again, and again, and again.

-a
--
Austin Ziegler • halostatue@gmail.com <mailto:halostatue@gmail.com> •
austin@halostatue.ca <mailto:austin@halostatue.ca>
http://www.halostatue.ca/http://twitter.com/halostatue

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

I have to agree with Austin here. Die, I’ve generally stopped reading your emails to this group (unless I’m in a mood to be frustrated), because I know that you’re going to take some simple feature, do something odd with it, and then complain about the results. And then, when some well-intentioned reader tries to explain why what you’re doing is not appropriate, you argue with them.

Austin is right that *every* programming language will have some obtuse features. Assuming that you are really trying to accomplish what you say you want to do, instead of insisting that it should work the way you want it to, do one of two things:

1) Find out the “right” way to do it (there is often more than one, and different users may disagree on the right way, so find a way that works and makes sense to **you**).

2) Realize that maybe what you’re trying to do is not a good fit for the feature you’re trying to use and find a different feature to do it with. For example, it’s good practice to avoid using integers as Hash keys, simply because of the similarities between the syntax for a Hash key and and an Array index. Violate this principle at your own risk.

Further, it’s one thing to explore a feature, find what appears to be inconsistent behavior and point it out. It’s quite another thing, when others on this list invest their precious time responding to your post, to insult them by arguing (which you seem to do every time). Please recognize that if someone who responds to you really gives a poor argument or tells you something incorrect, someone else will definitely correct them.

I don’t normally respond to these sorts of occurrences, but you’ve been doing this for so long that I'm really tired of seeing it. Please stop!

···

On Jun 8, 2022, at 7:59 AM, Austin Ziegler <halostatue@gmail.com> wrote:

As I wrote, it's about the (strange - not coherent/consistent) "syntax"
you have to use to get what you want. I pointed out, that for Array it
is again another form.

Just stop. You have been trolling this mailing list for years, convinced that your view is the only correct view of Ruby and refusing to accept any mental model except your own. If, indeed, you actually know C, then you know that there’s places in C syntax where consistency simply doesn’t exist, as is the case with *any* programming language. Each and every instance of UB is a lack of consistency and clarity where one is invited to mess around and find out what your compiler does, because every compiler will do it differently.

In comparison, Ruby object instantiation is crystal clear *and* well-documented. Just because you can’t accept that the semantics are foreign *to you* does not make them surprising, unobvious, or anything except "foreign to you".

Let’s try to provide some education to readers of the thread, even though it will obviously not be you.

But (very) surprising for me is that h=Hash.new(); h[1] << 1 # we
should at least get a warning if changing the defaultval; nobody
expects after changing h[1], that (the key) h[1] does not exist,
although it's clear when understanding what is done.

Variables in Ruby are not locations. They are labels. In C, the expression `uint32_t a = b = 3` takes up approximately 8 bytes of stack memory. In Ruby, the expression `a = b = 3` takes up approximately one Object of memory (certain numbers are special in most implementations of Ruby, but that is an implementation detail about most numbers being "internalized").

Variables in Ruby are labels to *references* (to objects). Expressions in Ruby return *references* (to objects). With this minimal information, it becomes pretty easy to reason that `h = Hash.new()` gives me a reference to the Hash which I have labeled `h`. If I don’t understand why `h[1] << 1` modifies `h.default`, then I read some documentation and realize that even if I do `h[1]`, that does not necessarily mean `h.has_key?(1)` returns true because I provided a mutable default object. Or I could even see `h[1].object_id == h[2].object_id` returning a true value, and enlightenment might actually occur.

I might actually then be able to reason that `h[1] == h.default` because I’m really dealing with object references all the way down so that when I modify `h[1]` because `h.has_key?(1) == false`, I’m really modifying `h.default`. This isn’t something that would occur to a C genius, of course, because reading the fine manual would disabuse said genius of their ability to troll people on the same or similar topics again, and again, and again.

-a
--
Austin Ziegler • halostatue@gmail.com <mailto:halostatue@gmail.com> • austin@halostatue.ca <mailto:austin@halostatue.ca>
http://www.halostatue.ca/http://twitter.com/halostatue
Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>