You're probably aware of this but given that the ticksPerSecond property is merely a wrapper for the _ticksPerSecond backing variable
you can just collapse the code to
var _ticksPerSecond as decimal
pro ticksPerSecond from var
# or implicitly get the backing variable generated
pro ticksPerSecond as decimal from var
( the above gets expanded to the equivalent of your code anyway)
Generally you only need the full property form if the code blocks for getter and settor need to do a little more than just reflect
in or out a variables contents ( synthesize or calculate values, more validation code, trigger effects elsewhere (GUI update, Observers,...)
1) How to provide vars constants types to widespread program parts?
- import the namespace containing the values and access directly - namespace contents here are usually just Types, and enums and shared/static providers ( the enum could be pushed up to the Namespace level)
import ESUtils
...
a = Globalz.someConstant + 3
a = a + Globalz.MyRandom.next(7, 8)
#probably clearer in client code to give the full namespace and Object spec ( no import)
a = ESUtils.Globalz.someConstant + 3
a = a + ESUtils.Globalz.MyRandom.next(7, 8)
b) Make the container object a
Singleton - an Object that has only one instance no matter how many times it is 'instantiated'
Basically you hide the constructor so it cant be created outside the objects class, create another shared method that does the instantiation
storing the single instance local to the class - initial instantiation creates the object and stores it and returns the stored instance, subsequent ones just return the singleton instance.
For simple providers its common to mix the instantiation and use of singleton value in a single (shared) method
..
for your example (roughly)
class MyRandom inherits Random
shared
var _instance as Random # = Random()
cue init
base.init
def next(lowValue as int, highValue as int) as int #fix next from random class,
assert lowValue <= highValue
assert highValue + 1 <= int.maxValue
if not _instance # first call
_instance = Random() #, instantiate the singleton instance with whatever ctor values desired
#every other operation use singleton instance to provide the operation
return _instance.next(lowValue, highValue + 1)
# elsewhere use as
a = a + MyRandom.next(7,8) #if imported
...
b = 3 + Utils.MyRandom.next(10,20) # MyRandom in Utils namespace
Singletons are these days generally seen as a bad thing as they are still just basically dressing up a global variable/instance behind an OO facade. They're somewhat fragile in the face of changes since you often need change the caller code. ( google for 'Singletons considered harmful')
c) Make a
Factory class that is responsible for providing the Object to be worked on via a
factory method.
This is usually just another static class with a single static object returning method ( the factory).
A Factory is currently seen as superior because it is all code and amenable to extension/augmentation (inside the method ) without affecting the API call and or can be reconfigured to do something different if its execution environment (env variables, Property lookups, DB lookups ) is tweaked to generate different results. Also the strategy for the factory behaviour can often be provided in the factory rather than the returned class itself...
again very roughly
Namespace Factory
class Random
'''Factory class for production of Random generators of various capabilities all inheriting from System.Random()'''
var _single as Globalz.MyRandom
'''Singleton-ness functionality provided by factory'''
def single as System.Random is shared
if not _single
_single = Globalz.MyRandom() # passing any specific args
#_single = NonProduction.MyOtherRandom() #alternative randomGenerator
return _single
'''Alternative triggered by a string selector'''
def generator(pars as List of String) as System.Random is shared
if pars.contains('myrandom')
return Globalz.MyRandom()
if pars.contains('std')
return System.Random()
if pars.contains('test')
return TestRandom()
if pars.contains('bad')
return RandomNextAlwaysReturnsOne()
throw FallThroughException('Parameter not in "myrandom", "std", "test" "bad"')
'''Alternative triggered by a an underlying selector not part of caller API'''
def generator() as System.Random is shared
par = System.Environment('WhatRandom')
# could also read this from a properties file or other configurable lookup
if par == 'myrandom'
return Globalz.MyRandom()
if par == 'std'
return System.Random()
if par == 'test'
return TestRandom()
if par == 'bad'
return RandomNextAlwaysReturnsOne()
throw FallThroughException('Config error: getRandomGenerator parameter not in "myrandom", "std", "test" "bad"')
# Use like
a = a + Factory.Random.single.next(7, 8)
...
# or more likely
randm = Factory.Random.single
...
a = a+ randm.next(7,8)
...
b = 3 + randm.next(8, 16)
d) Charles solution - attach a handle/accessor/method/property for the useful thing to a common item (Object in this instance) using 'extends'.
This could be itself a factory generating an instance of the Object desired.
2) how do i access the MyRandom class from elsewhere in the program?
- pass the instance to the class to use
- instantiate and use the instance in the class - either as a normal instance or a Singleton
- access as a static method on a static class
- call a Factory for the instance (of whatever stripe is required) and use whatever is returned
Theres an old CompSci rule of thumb that
'Every computing problem can be solved by adding another layer of indirection'
apply that - creatively