Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Is it possible to create constant?


  • Please log in to reply
10 replies to this topic
BrandonHotkey
  • Members
  • 691 posts
  • Last active: Oct 21 2015 09:41 PM
  • Joined: 21 May 2012

Is it possible to create constant? And how? If I want to replace globals and use them as constants in the function, so I need not to declare them, because these value do not change...



dmg
  • Members
  • 2395 posts
  • Last active: Nov 04 2015 06:46 AM
  • Joined: 19 Nov 2010

I am not entirely sure what you are asking, but maybe this will help:

http://www.autohotke...ions.htm#Locals


"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion

-----------------------------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact

GeekDude
  • Spam Officer
  • 391 posts
  • Last active: Oct 05 2015 08:13 PM
  • Joined: 23 Nov 2009

I don't know about constants (which are read only), but you can create a "Super Global" by defining a global variable outside of a function. By doing so, that variable becomes global across all functions, without having to be specified.



Person93
  • Members
  • 443 posts
  • Last active: Feb 11 2014 12:07 AM
  • Joined: 26 Jan 2012

You can create a class that does not accept assignments and always returns a given value.

 

;------------------------------------------------------------
;This part must be in the autoexecute section of your script
;------------------------------------------------------------
class Constant
{
	__New(value)
	{
		this.saved := value
		this.locked := 1
	}
	
	__Set()
	{
		static count := 0
		count ++
		if (count > 2)
		{
			if (this.locked)
				return this.saved
		}
	}
	
	__Get()
	{
		return this.saved
	}
}
;------------------------------------------------------------
;End of class creation
;------------------------------------------------------------

;create your constant
MyConstant := new Constant("Hello World")

;retrieve your constant by using any random string as a key
MsgBox, % MyConstant.RandomString

;attempt to overwrite it and observe that it does not work
MyConstant.hi := 1
MsgBox, % MyConstant.hi


BrandonHotkey
  • Members
  • 691 posts
  • Last active: Oct 21 2015 09:41 PM
  • Joined: 21 May 2012

I don't know about constants (which are read only), but you can create a "Super Global" by defining a global variable outside of a function. By doing so, that variable becomes global across all functions, without having to be specified.

That sounds good



BrandonHotkey
  • Members
  • 691 posts
  • Last active: Oct 21 2015 09:41 PM
  • Joined: 21 May 2012

You can create a class that does not accept assignments and always returns a given value.

 

Also thanks. I think it could be also good. I have a gui form. After it is confirmed I want to save its values as constants. Your class will be very good for this.

 

Structure of my script, could it be like so?

 

; starting block
IniRead,upToPlayer, %config_file%, Common,upToPlayer


; gui block
Gui, Add, DropDownList, x137 y71 vupToPlayer w70, % _SetDefaultItem("list","this one|1|2|3|4|5|6|7|8","|",upToPlayer)

; submit block
Const := new Constant("Hello World")
IniWrite,%upToPlayer%, %config_file%, Common,upToPlayer  

; start main core of the script, where I call functions and access the Const


BrandonHotkey
  • Members
  • 691 posts
  • Last active: Oct 21 2015 09:41 PM
  • Joined: 21 May 2012

May you please help with modification? I would like to manage the constants into "groups". Fist group is general constants. Second group is array of conditions (every condition has same set of constants). Last group is effects, they are also array and every effect has same set of constants.

 

I tried to create this class for general according your object, but IDK how to add the constant into the object and now to access it.

 

class Conf
{

    __New()
    {
    if (!count) Objects := {}
      Objects.Insert(ConstObj)
    }


    __Set()
    {
        static count := 0
        count ++
        
    }


    __Get(key)
    {
        return this.Objects[key]
    }
}
 

 

 

Create new objects with condition settings and save it to condition[0], condition[1], condition[2]:

 

condition := new Conf({some object here})
condition := new Conf({some object here})
condition := new Conf({some object here})
 


Person93
  • Members
  • 443 posts
  • Last active: Feb 11 2014 12:07 AM
  • Joined: 26 Jan 2012

If you want an array of constants, create an array in which each element is a class object.

 

The way the class is set up, there is no way to add a constant once its created, you need to create a new object for each constant.



BrandonHotkey
  • Members
  • 691 posts
  • Last active: Oct 21 2015 09:41 PM
  • Joined: 21 May 2012

I have decided to do it a bit different, to use dynamic properties if possible. I am also finished, but stucked in the point, that I can __Set only one property with same name. But what is my plan, I want to call the object like

 

c := New Conf(0)
c.player:=1
c.upToPlayer:=8
c.next(1) ; the number 1 switches to next set (next element of array)
c.player:=1
c.upToPlayer:=8
c.next(2) ; next set of values to come...
 

http://www.autohotke...mic-properties/

 

If you could help to finish the thing with dynamic properties I would be very thankful...



sirksel
  • Members
  • 3 posts
  • Last active: Dec 08 2015 08:38 AM
  • Joined: 15 May 2013

Is it possible that Lexikos or others could revisit this topic of global constants?  Over five years, I've written 10K+ lines of AHK code for my personal macro script, and I'm refactoring some of that now.  A lot of that is MSOffice automation in AHK using COM.  Global constants would be helpful, if for no other reason than being able to use them to specify default parameters for functions.
 
For an oversimplified example, suppose you're writing a multipurpose ExcelAlign() function to align some text in selected cells in Excel, depending upon an alignment type passed as a parameter.  AHK's great COM integration lets you do that easily.  If you want however to add a default alignment type and you want to be clear about the defaults, I usually do this:

global xlCenter := -4108,  xlLeft := -4131

ExcelAlign(aligntype="") {
    if (aligntype == "")
        aligntype := xlCenter
    ; ... do the actual COM work here
}

ExcelAlign()  ; to get the default behavior
ExcelAlign(xlLeft)  ; get a different behavior using a different global

You can't use the function header Align(aligntype=xlCenter) because you can't use a variable as a default parameter -- for obvious reasons.

 

It would be really great if I could replace the above code with something like the following:

const xlCenter := -4108
 
ExcelAlign(aligntype=xlCenter) {
    ; ... do the actual COM work here
}

That code is clearer and more efficient, and you can get right to the automation work.  Since this is a simple example and many office automation tasks have quite a few parameters (most of which I write with defaults), setting defaults by setting/checking ="" 5+ times on different parameters puts a big block of not-so-necessary code at the beginning of my functions -- and there are hundreds of these functions.  For example, an ExcelFind function/method might be able to then have the following header which could use constants...

ExcelFind(str, startAt, lookAt=xlWhole, searchOrder=xlByRows, searchDirection=xlNext, matchCase=0)

Without constants, I have to do three if blocks to handle the temporary "" defaults instead.  I suppose I could also just assign the nonsensical integer defaults directly in the header and then document what the integers mean in a comment below... but I'd still need the global var for the many instances where the function gets called.  That seems ugly and harder to debug, since the same numeric literal would be written out in multiple places (the global, the header, the documentation).  A global constant seems so much cleaner!
 

Also, as a side effect of implementing constants for this purpose, you would also address the request for differentiated NULL that others have brought up in other threads, which could simply be accomplished with a constant/sentry:
 
This code...

global NUL := "#@NUL"  ; sentry that is unlikely to appear in a real string
 
myfunc(strA="#@NUL", strB="#@NUL", strC="#@NUL") {  
    ; where the passed value could be "" and we need to differentiate from missing
    if (strA == NUL)
    ...
}

 ...could become a little bit simpler/clearer in its function header with constants: 

const NUL := "#@NUL"  ; sentry that is unlikely to appear in a real string
 
myfunc(strA=NUL, strB=NUL, strC=NUL) {
    if (strA == NUL)
    ...
}

Lexikos, I know you and others are busy, and I very much appreciate all the time you've put into making AHK the great language it is.  If you wouldn't mind taking a look at this "global constant" topic one more time, it would be very much appreciated.



Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

... you can't use a variable as a default parameter -- for obvious reasons.


I don't think it's obvious. What are the reasons?

It's certainly feasible, but I think it would add (a very small amount of) overhead to a possibly performance-critical section of the code. Or at least, it did last time I tried to implement it. I've forgotten the reason I put that experiment aside.

Global constants would be helpful, if for no other reason than being able to use them to specify default parameters for functions.


There are really two wishes here:
1) Add constants.
2) Allow something other than a simple literal value as a parameter's default value.

You've given a good case for #2, but not for #1.

The benefit that constants would provide for default values is that a constant can be replaced at load time with the corresponding value (adding code to a non-critical section), eliminating any possible performance penalty. However, it would be more complicated if a constant can be initialized with an expression, like const WM_MYMSG := (WM_USER + 42).