Luc <
luc@sep.invalid> wrote:
On Tue, 25 Jun 2024 22:29:46 -0000 (UTC), Rich wrote:
If you only *ever* have one dog, either are essentially the same.
>
But, if at some point you want to manage spot, frank, sam, donut, and
alexa, all of which are different dogs, then you can do:
>
snit::type dog {
method {tail wag} {} {return "Wag, wag"}
method {tail droop} {} {return "Droop, droop"}
}
>
Once to create a generic "dog" framework.
>
And then later do, all in the same single program instance:
>
dog spot
dog frank
dog sam
dog donut
dog alexa
>
And have five, fully independent dogs (each with their own independent
"data") that you can manipulate, without having to do anything special
at the time you create them.
>
I.e., you can wag spot's tail, give food to sam, and label alexa with
"last vet visit was 2024-06-21" (assuming you had mentods for 'feed'
and for 'last-vet-visit' in the generic framework.
And how is that better than this:
proc dog {dogname args} {
if {$args == "tail wag"} {return "$dogname Wag, wag"}
if {$args == "tail droop"} {return "$dogname Droop, droop"}
if {$args == "eats food"} {return "$dogname Nom, nom"}
if {$args == "goes to vet"} {return "$dogname Tries to run"}
}
puts [dog fido tail wag]
puts [dog lucky tail droop]
puts [dog charlie eats food]
puts [dog mitts goes to vet]
That will handle multiple dogs pretty well.
One "method," one "if." It's pretty much it, isn't it?
Robert explained that your one 'if' is going to get pretty unweildy
very fast, esp. if you have different dogs with different behaviors.
I.e., fido can fetch, lucky refuses to fetch but will chew your
slippers, charle will roll over and fetch, but never chews your
slippers.
But, you are focused on the "call method" part of objects, and that's
not the part that makes objects actually useful. It's helpful, but the
real value is the fact that each object is an isolated little block of
data (with a set of procs that know how to access and manipulate that
data).
A better example than the "dog" one for objects and the data
encapsulation aspects is to instead think "bank accounts" (this won't
be proper snit syntax below, but hopefully you'll follow):
snit::type savings {
variable balance 0 ;# assume this initalizes 'balance' to zero when a
#new object of type 'savings' is created
method deposit {amount} {
set balance [expr {$balance + $amount]
}
method withdraw {amount} {
set balance [expr {$balance - $amount]
}
method inquire {} {
return $balance
}
}
Now we create accounts for fred and barney:
savings fred
savings barney
And we have two objects, "fred" and "barney" that both have a
"balance" variable, but... their balance variables are actually
separaate (you would not want your bank account to be "shared" with
everyone else who banks at that bank, right).
So if fred deposts 20, you can do:
fred depost 20
Then, if you 'inquire' about the balances you get:
fred inquire
20
barney inquire
0
Different answers, because each object has its own unique set of
variables (i.e., data) that is private for just it. Whatever you do to
barney's account, fred's balance remains the same.
This is where the real 'magic' of objects starts to show it's value.
You were building someing some months ago where I pointed out that
you'd accidentially worked your way into building a very simple object
by accident. IIRC you were trying to track multiple windows in a text
or on a canvas for something, and you'd created a set of namespaces or
something, one per each window, to store the variables needed for that
window apart from the others.
Had that been 'objects' from the start, you'd have created a class that
defined the variables each window needed, and the methods to act on
those variables (and update the window contents) and then you could
have just created "new" objects, one per window, and had all the
framework of separate variables and procs all taken care of by the OO
system.
And since objects can have an 'initializer', you could have had the
creation of the object also create the window associated with the
object automatically, and store away the window names in object
variables to use to manipulate the window. And a finalizer to destroy
the windows that were created when the object was destroyed. So you
could have done:
win new abc
and gotten the window created, plus all the 'procs' to do things with
the window, and then when done with it called
abc destroy
and had the windows also destroyed and all the variables deleted that
were part of the object -- all automatically.