Global Variables

If you have any questions, remarks, ... if you need help... its here...

Global Variables

Postby Will.Rubin » 08 Feb 2016 21:55

Hi,

Any way of making a global variable?
Looking for a way to hold a StringBuffer (for example) outside of a function, but need it named so I can refer to it within a function w/o having to pass on stack.

--Will
Will.Rubin
 
Posts: 10
Joined: 16 Dec 2014 17:00

Re: Global Variables

Postby Franck » 08 Feb 2016 22:40

Hi,

There is nothing global and mutable in Oforth and there is no synchronisation between tasks (mutexes, semaphores, ...) because tasks never share mutable objects.

At the global level, you have constants and words, and they are immutables objects, so there is no problem for parallel tasks to access them.
Communications between tasks are done using channels and you can pass immutable objects from one task to another using a channel.

Ok, this does not answer your question :) but it is to show you that Oforth does not like global mutable objects and prefers immutable objects.

There are 3 ways to do what you want :

1) Pass the stringBuffer as parameter to functions of methods that need them.

2) Use immutable objects instead of a StringBuffer

3) Use a TVar.
A TVar is a variable global to a particular task.
Each task will have its own value of a TVar and this value can be mutable.
This is absolutly not a way to allow mutable objects to be shared by tasks.
Of course, if you have only one task (the interpreter), a TVar is like a global variable.

A TVar value can be read/write using #at and #put.
(and #inc and #dec increment or decrement a TVar value).

Code: Select all
tvar: MYSTRING
StringBuffer new MYSTRING put


But, again, in Oforth, it is better to work with immutable objects.

If you tell me what you want to do, I could tell you if a TVar is ok or not (or if there is another option).

- Franck.
Franck
 
Posts: 144
Joined: 29 Oct 2014 19:01

Re: Global Variables

Postby Will.Rubin » 08 Feb 2016 23:59

This is in relation to the Rosetta Code tasks. My idea was to be able to create the task code and the output results within the same code for ease in making it testable. But I didn't want this to compromise the simplicity and readability that should be present for a task.

Take for example the Towers of Hanoi task.

The existing (corrected) code is simply:
Code: Select all
: move(n, from, to, via)
   n 0 > ifTrue: [
      move(n 1 -, from, via, to)
      System.Out "Move disk from " << from << " to " << to << cr
      move(n 1 -, via, to, from)
      ] ;

move2(3, $left, $middle, $right)


But to put it into a testable single .of file the best I could do was something along the lines of:
Code: Select all
: move2(n, from, to, via, log)
   n 0 > ifTrue: [
      move2(n 1 -, from, via, to, log)
      log "Move disk from " << from << " to " << to << "\n" << drop
      move2(n 1 -, via, to, from, log)
   ] ;

// this is just thinking about local variables and scopes. Not a requirement for the task.
: test  // ( -- log )
  | log |
  StringBuffer new ->log
  move2(3, $left, $middle, $right, log )
  log ;
 
test

"Move disk from left to middle
Move disk from left to right
Move disk from middle to right
Move disk from left to middle
Move disk from right to left
Move disk from right to middle
Move disk from left to middle
"
==
.s


This leaves move2 like move, but I've got no way to get log into the function without adding it as a parameter. I think the parameter removes clarity.
Being able to add a global
Code: Select all
StringBuffer new ->log
like construct would remove need to pass the StringBuffer.

--Will
Will.Rubin
 
Posts: 10
Joined: 16 Dec 2014 17:00

Re: Global Variables

Postby Franck » 09 Feb 2016 00:23

Ok, I agree that the string buffer should not be sent as parameters to words to log.

But, what will you do with the stringbuffer returned by #test ? Just print it ? Check its value ? Put it into a file ?
What do you mean by "testable" ?

Franck
Franck
 
Posts: 144
Joined: 29 Oct 2014 19:01

Re: Global Variables

Postby Will.Rubin » 09 Feb 2016 01:33

I don't really want it returned to test. The test function was just me playing around a bit. I was thinking about scope and potentially creating a closure of some sort but stopped there when something else came up. So #test would be removed in the real deal. (I had just copy/pasted all the code in my file.)

Edit: Realized my post with the code missed the second half. That explains your reply. My bad.

Here's the missing bits:
Code: Select all
test: [
// log
"Move disk from left to middle
Move disk from left to right
Move disk from middle to right
Move disk from left to middle
Move disk from right to left
Move disk from right to middle
Move disk from left to middle
"
== ]


This way the "output" section for the RC task can appear within the test too. (For easy copy/paste to their site.)
Will.Rubin
 
Posts: 10
Joined: 16 Dec 2014 17:00

Re: Global Variables

Postby Franck » 09 Feb 2016 19:48

Well, then you have two choices : the simple one and the less simple one.

1) The simple one is to create a TVar :
Code: Select all
tvar: LOG
StringBuffer new LOG put
LOG at "Move disk from " << from << " to " << to << "\n" << drop


but, of course, there are restrictions about tvars (value is not shared among tasks).


2) The less simple one is to use an accumulator.
The idea is that a channel is an immutable object : it represents the pipe between
tasks. So you can use a channel to hold the current value of the LOG.

If interested, you can see this rosetta code task :

http://rosettacode.org/wiki/Accumulator_factory#Oforth

Franck
Franck
 
Posts: 144
Joined: 29 Oct 2014 19:01


Return to General

Who is online

Users browsing this forum: No registered users and 3 guests