Thread from comp.lang.tcl (7 replies)
Lost in Ashok's teachings
I am trying to learn from this page: https://www.magicsplat.com/articles/oo.html It is written by the legendary Ashok. The author that so many people here so often rush to recommend. I am not getting along well with it. His first lesson: create a class: % oo::class create Account Next lesson: defining data members: % oo::define Account { variable AccountNumber Balance } Then, defining methods: oo::define Account { method UpdateBalance {change} { set Balance [+ $Balance $change] return $Balance } method balance {} { return $Balance } method withdraw {amount} { return [my UpdateBalance -$amount] } method deposit {amount} { return [my UpdateBalance $amount] } export UpdateBalance } Sadly, Ashok embraces the most traditional way of teaching programming=20 or anything related to IT: assuming the reader is some kind of ChatGPT sponge that can instantly absorb all and any information that is fed along the way, so he distracts me with a lot of additional information=20 that I REALLY think should only be fed later, and which I am skipping here. But I had to take note of this: "Methods that begin with a lower case letter are exported by default.=20 Thus in our example, deposit and withdraw are exported methods while=20 UpdateBalance is not. Method visibility can be changed by using the=20 export and unexport commands inside a oo::define class definition script.=20 Thus oo::define Account {export UpdateBalance} OK. I did that. So here is my script: ----------- oop.tcl ----------------- oo::class create Account oo::define Account { variable AccountNumber Balance } oo::define Account { method UpdateBalance {change} { set Balance [+ $Balance $change] return $Balance } method balance {} { return $Balance } method withdraw {amount} { return [my UpdateBalance -$amount] } method deposit {amount} { return [my UpdateBalance $amount] } export UpdateBalance } ---------------------------------- And he provides zero information on how to USE that thing. Zero.=20 Instead, he goes on and on about a lot of other information that I=20 REALLY think should be reserved for later. Finally, I run into "3. Working with objects" % set acct [Account new 3-14159265] % Account create smith_account 2-71828182 OK. So I add those two lines to my script. Upon running it, no complaints by the compiler. But there is no output either. Let's add some action: ----------- oop.tcl ----------------- oo::class create Account oo::define Account { variable AccountNumber Balance } oo::define Account { method UpdateBalance {change} { set Balance [+ $Balance $change] return $Balance } method balance {} { return $Balance } method withdraw {amount} { return [my UpdateBalance -$amount] } method deposit {amount} { return [my UpdateBalance $amount] } } oo::define Account {export UpdateBalance} set acct [Account new 3-14159265] Account create smith_account 2-71828182 $acct deposit 132 ---------------------------------- There, I broke the toy. can't read "Balance": no such variable while executing "+ $Balance $change" (class "::Account" method "UpdateBalance" line 2) invoked from within "my UpdateBalance $amount" (class "::Account" method "deposit" line 2) invoked from within "$acct deposit 132" (file "oop.tcl" line 41) Compilation failed. I tried a lot of ideas and all of them run into the same problem: the compiler has no knowledge of this Balance variable I speak of. Reading on, I find this: 3.3. Invoking methods This is the form used to invoke a method on the object from code=20 =E2=80=9Coutside=E2=80=9D the object. % $acct balance =E2=86=92 1000000 % $acct deposit 1000 =E2=86=92 1001000 Oh yeah? OK. Let's add those lines to the script then: $acct balance can't read "Balance": no such variable while executing "return $Balance " (class "::Account" method "balance" line 1) invoked from within "$acct balance" (file "oop.tcl" line 41) Compilation failed. $acct deposit 1000 can't read "Balance": no such variable while executing "+ $Balance $change" (class "::Account" method "UpdateBalance" line 2) invoked from within "my UpdateBalance $amount" (class "::Account" method "deposit" line 2) invoked from within "$acct deposit 1000" (file "oop.tcl" line 41) Compilation failed. I wonder if the code provided in the explanation is really correct and tested. Why is the 'Balance' variable adamantly not recognized? I am also intrigued by this line: set Balance [+ $Balance $change] Where did he ever define '+' as a command? There is zero explanation of it. I am very confused. Any comments, please? --=20 Luc >>Click on article to view all threads in comp.lang.tcl
Re: Lost in Ashok's teachings
* Luc <luc@sep.invalid> | ----------- oop.tcl ----------------- | oo::class create Account | oo::define Account { | variable AccountNumber Balance | } > | oo::define Account { | method UpdateBalance {change} { | set Balance [+ $Balance $change] | return $Balance | } | method balance {} { return $Balance } | method withdraw {amount} { | return [my UpdateBalance -$amount] | } | method deposit {amount} { | return [my UpdateBalance $amount] | } | } > | oo::define Account {export UpdateBalance} | set acct [Account new 3-14159265] | Account create smith_account 2-71828182 | $acct deposit 132 | ---------------------------------- > | There, I broke the toy. > | can't read "Balance": no such variable | while executing | "+ $Balance $change" | (class "::Account" method "UpdateBalance" line 2) | invoked from within | "my UpdateBalance $amount" | (class "::Account" method "deposit" line 2) | invoked from within | "$acct deposit 132" | (file "oop.tcl" line 41) | Compilation failed. > | I tried a lot of ideas and all of them run into the same problem: | the compiler has no knowledge of this Balance variable I speak of. You have ommitted the constructor from Ashoks example which initializes the 'Balance' variable. In your class, this variable is simply not initialized, which leads to the error. This is the same with every variable in TCL: global foo set foo => can't read "foo": no such variable namespace eval foo { variable bar set bar } => can't read "bar": no such variable You need to initialize (=set) a variable before you can use it. How the initialization is done depends on the context. namespace eval foo { variable bar init-value set bar } => init-value Thus if you have variables in a class, you most probably need a constructor to initialize them. This is also true for many OO languages... HTH R'Click on article to view all threads in comp.lang.tcl
Re: Lost in Ashok's teachings
On Thu, 26 Sep 2024 11:21:14 +0200, Ralf Fassel wrote: >You have ommitted the constructor from Ashoks example which initializes >the 'Balance' variable. In your class, this variable is simply not >initialized, which leads to the error. True. Thanks. What about that plus sign? Where is it defined? -- Luc >>Click on article to view all threads in comp.lang.tcl
Re: Lost in Ashok's teachings
On 9/26/2024 6:45 PM, Luc wrote: > On Thu, 26 Sep 2024 11:21:14 +0200, Ralf Fassel wrote: > >> You have ommitted the constructor from Ashoks example which initializes >> the 'Balance' variable. In your class, this variable is simply not >> initialized, which leads to the error. > > True. Thanks. > > What about that plus sign? Where is it defined? > > Replace it with tcl::mathop::+ Somewhere earlier in the book, I think I mention that the rest of the book assumes a "namespace path tcl::mathop" which is why there is that standalone "+". Was a bad idea in hindsight just to save the clutter of tcl::mathop:: prefixes everywhere. Regarding the code testing, the book build process runs every snippet of code and the output generated in the book is actually from running each example at book build time. Very few exceptions to that. Any errors abort the build process. The OO code should therefore run without errors (in the book, not sure of the online version which was an earlier draft). As for the rest of your comments, fair enough that you do not like the approach. You might try the other books in this space, like the one from Clif Flynt, or the online tutorial at https://wiki.tcl-lang.org/page/Tcl+Tutorial+Lesson+OOP1 /AshokClick on article to view all threads in comp.lang.tcl
Re: Lost in Ashok's teachings
* Luc <luc@sep.invalid> | On Thu, 26 Sep 2024 11:21:14 +0200, Ralf Fassel wrote: | What about that plus sign? Where is it defined? That is TCLs mathop: https://www.tcl-lang.org/man/tcl/TclCmd/mathop.htm % namespace path {::tcl::mathop} % + 4 5 9 See also https://wiki.tcl-lang.org/page/tcl%3A%3Amathop?R=0&O=mathop&W= HTH R'Click on article to view all threads in comp.lang.tcl
Re: Lost in Ashok's teachings
Luc <luc@sep.invalid> wrote: > On Thu, 26 Sep 2024 11:21:14 +0200, Ralf Fassel wrote: > What about that plus sign? Where is it defined? A bit of 'context' would help us in actually knowing to what you are referring. I'm assuming you mean this construct from your original post: [+ $var $var] That + is the "proc" version of the addition operator. It is accessible as either: $ rlwrap tclsh % ::tcl::mathop::+ 1 2 3 % Or by setting up a namespace path within your current namespace, which then allows you to call the proc without the absolute namespace names: % namespace path {::tcl::mathop} % + 3 4 7 You can also access the math functions (i.e., sin(), abs() etc) in a similar way (they exist in ::tcl::mathfunc::) % namespace path {::tcl::mathop ::tcl::mathfunc} % sin .2 0.19866933079506122 % abs -4 4 Presumably, somewhere in an earlier chapter of Ashok's book, he detailed the above little setting to be able to call the math operators (and/or functions) as procs. But as the full book is not on the web, you would not have had the benefit of having read that material prior to reading the OO chapter that is available.Click on article to view all threads in comp.lang.tcl
Re: Lost in Ashok's teachings
On Thu, 26 Sep 2024 22:17:46 +0530, Ashok wrote: >Replace it with tcl::mathop::+ >Somewhere earlier in the book, I think I mention that the rest of the >book assumes a "namespace path tcl::mathop" which is why there is that >standalone "+". Was a bad idea in hindsight just to save the clutter of >tcl::mathop:: prefixes everywhere. ************************** On Thu, 26 Sep 2024 18:53:11 +0200, Ralf Fassel wrote: >That is TCLs mathop: > https://www.tcl-lang.org/man/tcl/TclCmd/mathop.htm > > % namespace path {::tcl::mathop} > % + 4 5 > 9 > >See also > https://wiki.tcl-lang.org/page/tcl%3A%3Amathop?R=0&O=mathop&W= ************************** On Thu, 26 Sep 2024 22:28:17 -0000 (UTC), Rich wrote: >You can also access the math functions (i.e., sin(), abs() etc) in a >similar way (they exist in ::tcl::mathfunc::) > > % namespace path {::tcl::mathop ::tcl::mathfunc} > % sin .2 > 0.19866933079506122 > % abs -4 > 4 ************************** I was aware of math operations, but have used them very rarely if ever, so I didn't make the connection. Most important, I had no idea we could overload our entire code with all the math operations by importing a namespace. I'm not sure I like it, but it's good to know. As usual, I am glad I asked despite my usual hesitation. I always end up learning when I ask. Many thanks. I really appreciate it. -- Luc >>Click on article to view all threads in comp.lang.tcl
Re: Lost in Ashok's teachings
Luc <luc@sep.invalid> wrote: > > I was aware of math operations, but have used them very rarely if ever, > so I didn't make the connection. Most important, I had no idea we could > overload our entire code with all the math operations by importing a > namespace. I'm not sure I like it, but it's good to know. Small nitpick, "namespace path" is not "importing a namespace". Importing is an entirely different operation, with its own command to cause an 'import' (i.e., 'namespace import'). The "namespace path" works in a way analagous to the "PATH=" environment variable for Unix shells. It gives the Tcl interpreter a list of "places" to look for commands when your code within the namespace attempts to call the command. I.e., what it does is when the command you are calling in your current namespace is not defined in that same namespace, then the interpreter looks in each namespace in the "path", and if it finds the command defined in one of those namespaces, that is the command that gets called. So, if you have this: namespace eval ::example { namespace path {::tcl::mathop} variable a [+ 3 5] } Then what happens when the interpreter is executing the variable command is it see's a call to "+". So first it looks for: ::example::+ But that is not defined (assume the above is the totality of the definition of ::example). So next it looks to each namespace in the "namespace path". I.e. it now looks for: ::tcl::mathop::+ And since that one *is* defined (by Tcl itself) it then executes ::tcl::mathop::+ with parameters 3 and 5.Click on article to view all threads in comp.lang.tcl