Powerbasic Museum 2020-B

General Category => General Discussion => Topic started by: Kent Sarikaya on September 23, 2007, 07:03:26 AM

Title: global variables
Post by: Kent Sarikaya on September 23, 2007, 07:03:26 AM
You could call me a fan boy of using Global Variables, I always use them and I think they simplify so many tasks, but I keep reading how they should not be used.

I have been trying to figure out how to eliminate using them, but all I come up with is passing it as parameters to every function that needs to use the values, it sure seems like lots of extra work. Is there another way to handle a value used in many routines, without having to pass it as a parameters to the routine or using global as the scope?

Thanks for any tips!
Title: Re: global variables
Post by: José Roca on September 23, 2007, 07:46:19 AM
 
No. There is nothing wrong in using global variables if you don't intend to make your code reusable. If you want to be able to reuse the functions in another application, then avoid them.
Title: Re: global variables
Post by: Charles Pegge on September 23, 2007, 08:04:25 AM
If your population of global variables is fairly small, say less than 200, then that is perfectly manageable.

Another alternative is to arrange your variables into user- defined TYPES and pass these to your functions just the way it is done with many Windows calls. These types are normally passed BYREF, (which is the default mode in BASIC), only the address is passed so the call can be almost as efficient as using GLOBALs.

It all depends on the size and complexity of your program and whether you intend deploying your functions in other programmes. Having their own data structures might improve their portability.

But I find that many of my procedures require access to many 'state' variables which are shared throughout the programme, for instance when extracting a word in a script, it is useful to know its starting position, ascii code, its end position, then the  ascii code of the next word, and ascii code of the  previous word, and whether it is a number or a symbol - and which string was being read.

Similarly in a physics engine all the interacting objects need to know each other's positions, mass, velocity etc. Keeping them isolated would add to the complexity of the program.

Title: Re: global variables
Post by: Jim Robinson on September 23, 2007, 08:26:56 AM
There is nothing wrong using global variables as long as you are aware of the possible problems that you may encounter by using them.

I preface my global names with 'g' (like gsName, giCount, etc.) so that I will know I am dealing with a global if I need to go back and maintain the code. I generally do not use as many globals in my more complicated projects since it becomes a chore keeping track of them.  But, I will only change globals to locals if I really need to, not because someone thinks they are bad.

Like GOTO, global variables have received a bad name, and some people will tell you not to use them without knowing why.

Slightly OT: Once, as a joke, I told a COBOL programmer about a bumper sticker I saw that said "Real programmers use GOTO".  I received a 20 minute lecture on why I should not use the evil GOTO.  He was so passionate in his argument he actually turned red in the face.    ::)  (I had to listen to the lecture because he was a prospective customer.)
Title: Re: global variables
Post by: Paul Squires on September 23, 2007, 03:41:23 PM
In my programs I have a TYPE that holds all global variables.

For example:


TYPE GLOBAL_TYPE
  hSomething As Long
  nCount     As Long
  zString    As Asciiz Ptr
  '.... etc....
END TYPE

Global g As GLOBAL_TYPE


In my code, all I have to do is refer to the global as g.hSomething, or g.nCount, etc....

The only problem is when it comes to dealing with strings in the TYPE. Because PB does not have native support for variable length strings in a TYPE structure, I need to use my own routines for dealing with the string.


MemString g.zString, "This is my long global string"

MsgBox g.@zString


It is easy, clean, and simple to keep track of.


Title: Re: global variables
Post by: Theo Gottwald on September 23, 2007, 06:10:02 PM
Did you see the discussion on this topic here?

There is a clear comment from Bob Zale on the topic.
Must say that I agree with him on this point.

http://www.powerbasic.com/support/pbforums/showthread.php?t=34964
Title: Re: global variables
Post by: Kent Sarikaya on September 23, 2007, 06:12:28 PM
Thank you for all the feedback and ideas. Glad to know globals are not the evil coding style many seem to make it on the web.

The idea of passing globals in a UDT is very clever, THANKS. I will definitely try this. It is really a cool idea!!
Title: Re: global variables
Post by: Kent Sarikaya on September 23, 2007, 06:20:44 PM
Quote from: Theo Gottwald on September 23, 2007, 06:10:02 PM
Did you see the discussion on this topic here?

There is a clear comment from Bob Zale on the topic.
Must say that I agree with him on this point.

http://www.powerbasic.com/support/pbforums/showthread.php?t=34964

Thanks for the link Theo, it adds a lot of useful information to the conversation and is convenient to link from here to there in the future!
Title: Re: global variables
Post by: Eros Olmi on September 23, 2007, 08:14:41 PM
I discuss this in other many post but worth to remember here again.
To store any dynamic string you just need 4 bytes (a long, a dword, it doesn't matter). How? Just use on the fly (RE)DIM ... AT
Any LONG can be used to simulate an OLE32 dynamic string overimposing a dummy string structure ((RE)DIM ... AT) at the same memory location of the LONG.

Let me know if anyone need any further info on how to do it.

Ciao
Eros
Title: Re: global variables
Post by: Theo Gottwald on September 24, 2007, 08:12:34 AM
Eros, I remember there was some source code from you on a workaround of implementing "dynamic strings into UDT's".

Anyway all those workarounds are not the real thing :-).
I really hope we get something more easy for the user in future, no matter whats under the hood.
Title: Re: global variables
Post by: Eros Olmi on September 24, 2007, 10:48:28 AM
From a compiler point of view it is not easy, and I do not think dynamic strings inside UDT should be managed directly by the compiler. At the end they are just a 32bit pointer.

How can the compiler knows about the string?
After compilation, an UDT is just a sequence of bytes. If a dynamic string exists inside an UDT, the compiler need to store some special info to know that and to be able to manage accordling.

How can the compiler knows when to free allocated memory?
Ok, imagine the compiler generate code that knows, at runtime, that an UDT has one or more dynamic strings inside. I imagine that when the UDT variable is released, code takes care automatically also of the dynamic strings inside the UDT. Sometimes you allocate data but want full control of when releasing it. It happen quite often. I do not want the compiler "think" by itself!

I'm quite convinced that it is programmer responsability to deal with those data.
Title: Re: global variables
Post by: Theo Gottwald on September 24, 2007, 11:06:42 AM
You see, everything is possible at the end, if someone wants.

From mystandpoint as a user I, do not look on the obstacles the compiler makers have to go through.

The question for me as user is:

Can I easily rebuilt my "real-world" scenario into a "software data structure".
Because thats what its at the end about.

Questions like:
- How does the compiler make it internally to clean all the things up?
- is it difficult to adapt a SIZE() or VARPTR()?
is for the user of less interest.

If the question is: "Are UDT's with dynamic string useful" the answer is "YES".
Because IF dynamic strings are useful, then why should they not be useful in UDT's also.

Another point is, that if I look around it seems to be common for actual compilers to allow dynamic strings in UDT's (where is my Purebasic ...)?

Knowing that it can be formulated with Powerbasic as a workaround, I believed it could in the same way done "under the hood".
Even in the same reliable way. Because, if I formulate a workaround in PowerBasic and it works fine, why should it be worse if its builtin "under the hood"?

Title: Re: global variables
Post by: Eros Olmi on September 24, 2007, 11:20:08 AM
Yes, from a user point of view I can agree with you.

Dynamic string in UDT are possible in PureBasic?
I thought PureBasic does not even have standard variable as dynamic strings but only as ASCIIZ or fixed strings.
Are you sure? Because if this is true it will change ... "something" from my side about PureBasic consideration.

Title: Re: global variables
Post by: Paul Squires on September 24, 2007, 01:58:18 PM
I agree with Theo that it should be a built-in feature. Sure, there are several ways to accomplish it ourselves using pointers, but I bet that the new user would not know (or want to know) the methods of using pointers, dynamically allocated memory, or REDIM AT. I would guess that the majority of programmers do not program at the level of a Eros, Dominic, Chris, Theo, Jose, Patrice, etc...

.NET has STRUCTURE and CLASS data structures that replace TYPEs. I just looked them up on MSDN. I wonder if Microsoft cares if those data structures are saved and/or retrieved from disk?  ;)

I just looked through my source code for FireFly 3. It is amazing how much extra code that I had to write to handle all of the variable strings in my TYPE structures. Sure, it works, but it is messy and not "BASIC" like it should be. 

I guess we'll just wait and see what Bob decides to do. I sent in my suggestion to PowerBasic support.
Title: Re: global variables
Post by: Theo Gottwald on September 24, 2007, 01:58:35 PM
I am not 100% sure. Thats why I searched the link to my Purebasic shortcut :-).
I thought i remember something like that.

Btw. how is that in Freebasic?

@Paul, I like your suggestion with the VTYPE because then the old "TYPE " thing can stay as it is, and the new VTYPE could have own rules.
Title: Re: global variables
Post by: Charles Pegge on September 24, 2007, 02:20:33 PM
No problem at all in Freebasic

The structure defined below is actually 12 bytes long, so it must contain an FB string descriptor.

It's all down to what dynamic capabilities are included in the runtime.

Freebasic
type dynastringstruc
s as string
end type
                              '
dim dd as dynastringstruc     '

dd.s=string$(16000," ")       '
print sizeof(dd.s)            ' answer: 12
dd.s="hello world!"           '
print dd.s+"<<"               ' answer: hello world! (13 chars)
print sizeof(dynastringstruc) ' answer: 12
end




Title: Re: global variables
Post by: Eros Olmi on September 24, 2007, 02:22:52 PM
Quote from: Theo Gottwald on September 24, 2007, 01:58:35 PM
I am not 100% sure. Thats why I searched the link to my Purebasic shortcut :-).
I thought i remember something like that.

Btw. how is that in Freebasic?

Pure Basic strings are like C strings more or less so no native BSTR support

FreeBasic: it manages dynamic strings in a way quite similar to BSTR but handling structure have not the same layout. Quite pity because they were very similar. In any case BSTR can be managed using the many SysAlloc... OLE functions. So not big problems, just a little overhead. In any case, if I'm not wrong dynamic stgrings are possible inside TYPEs but you know, types in FreeBasic are now going to an OO view. See http://www.freebasic.net/forum/viewtopic.php?t=4504&highlight=dynamic+strings+inside+type
YES, THERE ARE BIG PROBLEMS: FB allows var-len string fields, but they aren't deallocated automatically when they go out of scope.. Post is Jun2006 so maybe this info is out of scope. But if not, we are at the same exact position of PowerBasic where the problem is memory de-allocation. For reference on FreeBasic string 12 bytes structure: http://www.freebasic.net/forum/viewtopic.php?t=3704

Those languages have the problem to keep compatibility between the systems they are present at high level priority.

I think the biggest problem to have dynamic strings inside an UDT is the release of memory. Whatever will be the method, compiler has be store the fact that extramem, other than the one of the UDT, has to be de-allocated. String handling is not the problem.
Title: Re: global variables
Post by: José Roca on September 24, 2007, 02:36:44 PM
 
Time ago, I asked for native support of VARIANTs inside structures. They can be used to manage any data type, even arrays of variants or object variables. With support for variants and object variables (if classes are implemented in a future version of the compiler) you will have everything. No need to "invent" new types of structures each time you want additional features.
Title: Re: global variables
Post by: Eros Olmi on September 24, 2007, 02:47:01 PM
That would be the perfect solution I think.

With variants you can store whatever you prefer. Of course it would be programmer responsability to free variant content in case of dynamic allocated content. For all numeric it would be automatically dealocated with the UDT.

Can be a great suggestion to solve the problem.

Title: Re: global variables
Post by: Eros Olmi on September 24, 2007, 02:53:05 PM
What about writing to support at powerbasic . com asking about this addition?

I see Mr. Zale is here and can read about that but official road is to ask at support. I remember that developed features have higher priority depending on how many customers asked about it.

Does it make sense to you to have variants inside UDT ?
Title: Re: global variables
Post by: José Roca on September 24, 2007, 03:00:40 PM
 
VARIANTs are the best solution because it covers all. If added native support for them inside structures, the only memory that you will need to release will be if you use a VT_BYREF variant to reference a pointer to memory that you have allocated, but no need to free strings nor arrays if you use safe arrays.
Title: Re: global variables
Post by: Eros Olmi on September 24, 2007, 03:07:12 PM
Are you sure?
I suppose it depends on how PB implements it. I mean if they just add 16 bytes and make VARIANT$, VARIANT# and VARIANTVT working on that 16 bytes, do you think memory will be released automatically? Who will release it if a dynamic string will be inside a VARIANT in a UDT structure? And what about OS before Win2K?

If it is all magically handled by some engine it would be fantastic and be the solution for all.
Title: Re: global variables
Post by: José Roca on September 24, 2007, 03:09:25 PM
 
With native support for variants inside structures, PB will have to call the VariantClear function for each variant when an UDT containing variants is going to be freed. This is what VariantClear does:

The function clears a VARIANTARG by setting the vt field to VT_EMPTY. The current contents of the VARIANTARG are released first. If the vt field is VT_BSTR, the string is freed. If the vt field is VT_DISPATCH, the object is released. If the vt field has the VT_ARRAY bit set, the array is freed.

If the variant to be cleared is a COM object that is passed by reference, the vt field of the pvarg parameter is VT_DISPATCH | VT_BYREF or VT_UNKNOWN | VT_BYREF. In this case, VariantClear does not release the object. Because the variant being cleared is a pointer to a reference to an object, VariantClear has no way to determine if it is necessary to release the object. It is therefore the responsibility of the caller to release the object or not, as appropriate.

In certain cases, it may be preferable to clear a variant in code without calling VariantClear. For example, you can change the type of a VT_I4 variant to another type without calling this function. Safearrays of BSTR will have SysFreeString called on each element not VariantClear. However, you must call VariantClear if a VT_type is received but cannot be handled. Safearrays of variant will also have VariantClear called on each member. Using VariantClear in these cases ensures that code will continue to work if Automation adds new variant types in the future.
Title: Re: global variables
Post by: Eros Olmi on September 24, 2007, 03:16:27 PM
Well, the idea is very clever but the way is not so simple.
Again, the compiler has to keep track of possible VARIANTs declared inside the UDT, and here again the same problem as dynamic strings mentioned above.

I personally would accept to have VARIANTs inside UDT even if the programmer will keep responsability to free them.
Of course if compiler will handle all those stuff I will be more happy :D

Title: Re: global variables
Post by: José Roca on September 24, 2007, 03:21:21 PM
Quote
Again, the compiler has to keep track of possible VARIANTs declared inside the UDT, and here again the same problem as dynamic strings mentioned above.

But with the same work, you add support for everything, not just for strings.
Title: Re: global variables
Post by: Eros Olmi on September 24, 2007, 03:24:11 PM
Hope Mr. Zale can get this suggestion.
For what it concernes to me, I will write down a request and I will send to support.
Title: Re: global variables
Post by: Charles Pegge on September 24, 2007, 03:31:48 PM
Thanks Eros, for your comments about Freebasic and deallocating strings in a UDT. Below is V1ctor's advice,
on how to release the string space before the structure goes out of scope.

Now I presume that if structures containing variants, were implemented in Powerbasic, we would still need some mechanism for releasing VARIANT strings and other referenced structures. Or are there OLE calls to do that for us?

Quote
FB allows var-len string fields, but they aren't deallocated automatically when they go out of scope, so if declaring/allocating them inside functions, remember to always set the fields to "" (including each item if it's an arrays of UDT's that contain var-len string fields) before exiting the functions or memory will leak.
Title: Re: global variables
Post by: José Roca on September 24, 2007, 03:36:39 PM
Quote
I personally would accept to have VARIANTs inside UDT even if the programmer will keep responsability to free them.

The purpose of having native support is to no have to handle memory management manually. Otherwise, you can have variants inside UDTs right now. Just declare a member of the structure as VARIANTAPI and use the various API functions to manage variants and safe arrays. A variant is just an structure, and PB allows to have structures inside structures.

Quote
Hope Mr. Zale can get this suggestion.

You bet. I have made already send this suggestion, and many others, to him.

Quote
Now I presume that if structures containing variants, were implemented in Powerbasic, we would still need some mechanism for releasing VARIANT strings and other referenced structures. Or are there OLE calls to do that for us?

See what I have posted about VariantClear above. It's time to learn some COM programming :)
Title: Re: global variables
Post by: Eros Olmi on September 24, 2007, 03:38:33 PM
Yes Charles, the problem is axactly how to determine the presence of a dynamic data (string or VARIANT) inside UDT and where and how release them.
Josè seems to have the exact idea on how to release, see above post from Josè.

In the meantime I'm writing my request to PB support to have VARIANTs in UDT. Will be a little voice, but you know, sea is made by little drops :D

Ciao
Eros
Title: Re: global variables
Post by: Paul Squires on September 24, 2007, 03:50:10 PM
The idea of using a VARIANT in a TYPE to handle variable strings is a great idea. It never occured to me. Using a VARIANT would certainly allow for a greater degree of flexibility.
Title: Re: global variables
Post by: José Roca on September 24, 2007, 03:54:12 PM
 
The "trick" is to use Automation compatible types, e.g. BSTR instead of ASCIIZ, safe arrays instead of other kind of arrays, object variables instead of pointers to custom allocated memory, etc. VariantClear knows how to manage them.

For a VT_BSTR variant, you allocate an string with SysAllocString and store the returned pointer in the structure. VariantClear will call SysFreeString to free the memory used by the string.

For a safe array, you allocate the memory and manage the elements using the API safe arrays functions. VariantClear will call SafeAerrayDestroy, that knows how to free the memory used by the array since a safe array includes information about the kind of data stored and the number of elements.

For an object variable, VariantClear will call the Release method of the object.

Now, if you want to use other kind of strings or arrays, then you will have to free the memory yourself, because VariantClear has no means to know how to do it.

For a perfect solution, just include another of my suggestions: native support for safe arrays.
Title: Re: global variables
Post by: Charles Pegge on September 24, 2007, 04:21:34 PM

Oops! I missed your COM post Jose, this topic is moving too fast!

COM and variants do not prevail in the Linux world, but the Variant structure is generic enough to be an open standard, and a very comprehensive one. Do we know if Microsoft considers the Variant and COM system as being Microsoft property. I find myself using very similar structures in $ and R$ to handle different data types and could very well adopt at least some of the standard. It would certainly improve interoperability, for low-level coding.
Title: Re: global variables
Post by: José Roca on September 24, 2007, 04:40:01 PM
 
You even can have structures containing variants, objects, etc., inside a variant. For that, you will need to learn some low-level COM programming and use the IRecordInfo interface. The possibilities are enormous...
Title: Re: global variables
Post by: Charles Pegge on September 24, 2007, 05:07:23 PM

Coming back to this global thing, most of my coding uses simple arrays of global strings. You can put dynamic structures inside strings and pass them anywhere by index. Then  memory allocation /  deallocation is never an issue. The string array can also be used as a stack, so that individual string elements are available for reuse.

The DIM .. AT .. when used in conjunction with strings is an especially useful feature of PowerBasic. - something I miss in FB.