This is more of varification, but i want to be sure before i start altering some old code to clean it up.
If you have private varibales declared inside a module but outside a subroutine, when are these actually created. For example, this is how a module is set up:
'Local objects.....
'Function Main.....
'Subroutines.......
Private Constants..
Private variables..
More Subroutines...
If those variables are only used in one subroutine, should they be declared inside that subroutine or in the local objects or right outside the subroutine as they are now?
Thanks!
The CLR has no support for modules or module variables so modules become static classes and module variables become static fields.
As a rule, variables should be declared as close to the point they are used as possible. Their scope should also be as constrained as possible.
Turning a variable into a field is a pretty bad coding practice for several reasons:
It is extremely easy to make a mistake and reuse the same field in another part of your module, creating unexpected conditions.
You increase the lifetime of the objects in the variable significantly. Typically, once you exit the method, the variable is available for garbage collection. By turning it into a static field, the object will stay alive until it's replaced or the application terminates
Multiple threads will be able to see and access the same static field, potentially creating race conditions. Given how many things work asynchrously nowadays, this can be a significant problem
Related
Finally, when I managed to understand how to fix this, that is, how to change the value of an internal dynamic variable, the code has moved on and now it is declared in this way:
my int $is-win = Rakudo::Internals.IS-WIN;
This is a class variable declared inside class Encoding::Builtin. Makes all the sense in the world, since an OS is not something that changes during the lifetime of a variable. However, I need to test this code from other OS, so I would need to access that class variable and assign it a True value. Can I do that using the meta object protocol?
The concept of "class variable" doesn't exist in Perl 6.
The declaration being considered is of a lexical variable, and its lifetime is bound to the scope (bounded by curly braces) that it is declared within. It doesn't have any relationship with the class that's being declared, so there's no way to reach it through the MOP. (That the block in this question happens to be attached to a class declaration is incidental so far as lexical variables go.) Nor is it declared our, so it's not stored in the package either.
The only way a lexical can be accessed - aside from under a debugger - is if something inside of that lexical scope explicitly made it possible (for example, by acquiring a pseudo-package and storing it somewhere more widely visible, or by allowing EVAL of provided code). Neither is happening in this case, so the variable not possible to access.
Perl 6 is very strict about lexical scoping, and that's a very intentional part of the language design. It supports the user in understanding and refactoring the program, and the compiler in program analysis and optimization. Put another way, Perl 6 is a fairly static language when it comes to lexical things (and will likely come to do much more static analysis in future language versions), and a dynamic language when it comes to object things.
In VB.Net can you declare variables locally (in a method) and have them have a global scope?
I'm new-ish to VB.Net and am trying to figure out some of the ways the language works. In a previous project I did with C++ I was able to inside of a method declare a variable as global, saving memory space until the first time that method was called and the variable was instantiated.
Just curious if this is something that is possible with VB.Net.
Encapsulation in .NET can make it difficult to implement a global variable in the way you are thinking of one. The closest solution may be to declare a public variable in a module, but it isn't immediately available inside another module.
The way I usually do what you're thinking is to create a singleton class "globals" that contains member fields representing the global variables I want to move around, then I just pass my "globals" instance as an argument.
Public Dim myGlobals as GlobalClass
myGlobals.someVariable = "preserve me"
Then making them available to be accessed by the method: someMethod(myGlobals) will pass them by reference by default.
So Jacob posted an pretty good answer to my question. After a bit more researching, I think my best bet is to do something similar to the following:
Class ScopeTest
Private randVar As Object = Nothing
Sub Initialize()
randVar = New Label()
End Sub
End Class
Essentially, create the variable at the highest level scope I need it, and set it to Nothing so that no data (should be) allocated to it, but the variable name has the appropriate scope. Then I just instantiate the variable whenever I call it the first time, and then it will be implemented throughout the rest of the code.
Obviously the largest pitfall with this setup is if I go to call the object while it is equal to Nothing. This will require me to add in some If Not IsNothing statements to the code, but since I can't seem to find a better way to go about this, it's what I will be doing at the moment.
The problem is that I've declared all my variables as public and simultaneously I'm passing those to subroutines.
Which solution is better and what are the differences?
BR
MichaĆ
The difference:
A public variable can be accessed from every module or routine within the workbook it has been declared in and can even be made accessible to other workbooks
A local variable can only be accessed by the module it was declared in
Try to avoid using public variables whereever you can. They might seem like the easy way out but can cause alot of problems the longer the code gets, use up unnecessary memory space and make the code structure quite confusing.
Passing values to a subfunction or -routine is usually the more elegant way and good coding practise.
I am writing a range of VBA functions / subs that can be reused in a number of projects. The issue I have is that these functions are listed in the suggested formula functions when using sheets.
Making the functions private will prevent this, but what it will also do is remove the handy hints showing the parameters for the functions when called from a module other than where the function is stored.
Does anyone know of a way to prevent the suggestion of custom functions without making them private?
Parameterless Public members of a standard module are one of two things:
Sub procedures and they're exposed as macros.
Function procedures and they're exposed as UDF's.
Note that members are implicitly Public if no access modifier is specified.
A Sub that has parameters can't be executed as a macro, so it won't show up as an available macro.
A Function that has side-effects (e.g. mutates some module/global state, or changes other cells' value) is bad code, and a UDF can't change another cell's value anyway.
Making the functions private will prevent this, but what it will also do is remove the handy hints showing the parameters for the functions when called from a module other than where the function is stored.
Making it Private not only "removes the handy hints", it makes the function inaccessible to other modules, and your code won't compile.
If your code has UDF's, put them all in the same standard module, e.g. UserFunctions, and make them explicitly Public for readability's sake.
If your code has macros, put them all in the same standard module, e.g. Macros, and make them explicitly Public for readability's sake.
If your code has functions and procedures that need to be Public (e.g. they're accessed from UDF's and/or macros), make them explicitly Public for readability's sake, and put them in standard modules named appropriately (i.e. avoid Helper and Manager modules, they inevitably become a dumping bag of whatever doesn't quite fit anywhere, and grow to a mess).
Then put this at the top:
Option Explicit
Option Private Module
That option (Private Module) prevents all public/exposed members from being picked up as macros and UDF's. Option Explicit should just be there anyway.
Another way is to implement logic in class modules; members of a class module can't be accessed without an instance of that class (i.e. an object), and therefore won't be exposed as macros/UDF's.
I have a global variable X in an winform application.
The variable X is used in different forms inside the application and I don't want it to be modified. It's not used as a parameter in the functions... so ByRef, or ByVal are not applicable.
It's used like that:
Declaration
dim X as whatever;
dim Y as whatever;
private sub SubExample(A as object)
'Do some staff
'Locally modifiy X
X = something else;
end sub
Main program
call SubExample(Y);
'After this, X should still have its original value
Any idea please ?
You can't protect a global variable (unless it has to be assigned only once, in that case it can be Const). By definition it's global so it's visibile by all classes.
I would avoid them every time it's possible because of that: you can't restrict their access to who really has to use it (as you found by yourself) and they couple all classes use them. Main problems I see with them are:
Testing: because they couple many (all?) classes they make code testing pretty hard. You can't really isolate a class or sub-system for testing.
Concurrency: they're free accessed by everything in any thread then you'll have concurrency issues and you'll need to make them thread-safe. A variable in VB.NET can be thread-safe (at least atomic read/write) only for primitive types.
Access: as you saw you can't restrict access to them. Even if you make them global properties you can just make them read-only but somewhere a write function/setter must exist (unless you're using them for singleton pattern or for other - few - corner cases).
Maintenability: your code will be harder to understand because implications won't be obvious and local.
What you can do to replace them with something more "safe"?
If you put them in a global class with Shared members just remove Shared and make them instance members. If they're in a Module just move them to a Class.
Make your class singleton (I would use a method instead of simple property to make this more obvious). This may or not be your case, you may simply create your object in your startup method.
Add a public property in each form will need them and when you create your form just set this property to class you previously created. According to effective implementation this may be or not a Context Object pattern.
If you have multiple sets of global variables (and each set has different users) you may need to create multiple classes (one class for each set of variables).
This is a pretty general method to quickly replace global variables, better way implies some deeper refactoring to make your code more OOP-ish but I can't say without a more complete view of your code.
As a low-tech solution, I would recommend using an unambiguous name like
Dim READONLY_X
as the name of your global variable. Then you are less likely to forget that you should not be writing a new value to it. When you feel the temptation to write the line:
READONLY_X = 2
it should ring an alarm bell. Wrapping inside getter functions etc (without the formalism of a class) seems like a kluge. But that's just an opinion.
As was said before, global variables are a pain; think carefully about the scope you want them to have, and whether there isn't another solution...