Jump to content

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

Should empty variables be treated as 0 in math expressions?


  • Please log in to reply
43 replies to this topic

Poll: Should math expressions treat empty variables as zero? (15 member(s) have cast votes)

Should math expressions treat empty variables as zero?

  1. No, an empty variable should produce an error. (5 votes [33.33%])

    Percentage of vote: 33.33%

  2. Yes, an empty variable should equal zero, but #Warn should provide notification of it. (5 votes [33.33%])

    Percentage of vote: 33.33%

  3. Yes, an empty variable should equal zero, and #Warn should not provide notification of it. (5 votes [33.33%])

    Percentage of vote: 33.33%

Vote Guests cannot vote
majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
After lot of conversation here I think it would be very good, especially for n00bs that AHK replace non existant variables in expressions with zeros:

So, if I have this ahk script:
 x := 5
 val := x + Y
 msgbox %val%

I wont to get 5 instead nothing. The above example will only work if I put Y := 0 somewhere before expression.

Alternatives are discussed in the topic I posted and can be sumarized as:

val := x + (0 y)                                ;doesn't work for y < 0
val := x + !(!y)*(0 Abs(y))*(1+(y<0)*-2)        ;mambo jumbo, working for y<0 
val := x + Round(y)                             ;doesn't work if y is float
val := x + VarExists(y)*y                       ;slow for multiple usage and more then 1 variable
val := x + (y Chr(!y*48))                        ; the best so far, still suffers for being slow for this task.


Alternative solution :

Directive #InitVars [value] so we can have both:
So this should report 5

 #InitVars    ;comment this line to return to old behavior

 x := 5
 val := x + Y
 msgbox %val%

OR


 #InitVars 1 

 x := 5
 val := x * Y
 msgbox %val%

Posted Image

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012

AHK replace non existant variables in expressions with zeros

Bad idea, it would break existing scripts.

val := x + !(!y)*(0 Abs(y))*(1+(y<0)*-2) ;mambo jumbo, working for y<0

I made that so it works if y is anything - positive integer, negative integer, zero, null/non existent, character, string, hex, etc... Explanation: !(!y) = boolean indicating y's existence; (0 Abs(y)) = 0 if y doesn't exist or y as an absolute integer with a prefixed zero (that makes no mathematical difference); (1+(y<0)*-2) = -1 if y is negative, 1 otherwise. Altogether the expression equals to 0 if y isn't an integer or y itself. You can easily make a wrapper function for this.

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

Bad idea, it would break existing scripts.

It was badly designed originaly, so it needs to be fixed. Existing scripts can be changed, to account this or it can be added in version 2, or with some new derecitve before version 2, witch will be used as default in v2 (like #FixExpresions :) )

You can easily make a wrapper function for this.

I can easily create wrapper for this, and kill my program that calculates things often. See VarExists explanation.


BTW, I do understand alien. Its not mumbo jumbo cuz its alien, but because it is overkill.
Posted Image

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005

it would be very good that AHK replace non existant variables in expressions with zeros

Not only non-existant variables but also empty variables:
a := 5
c := ""
b := a + c
MsgBox %b%
I admit I expected this to work when I started to code in AutoHotkey.

Bad idea, it would break existing scripts.

I doubt it, unless you have real examples for that. We don't use concatenation, but an arithmetic operation, so we expect automatic conversion that is done for other values to work here too.

Perhaps Chris has a good explaination for this behavior, I am ready to see it. Otherwise, it would be nice, indeed, to make this change. At worse, in the context of v2.

Note: Although I find the requested behavior more intuitive, I find bad practice to add up uninitialized variables...
Indeed, AutoHotkey made us lazy, we often start concatenating an unintialized variable with some value, so why not add up one, like allowing var++ before setting var := 0?

Or, a more consistent change would be to introduce the concept of null/nil value, that a variable would get before being initialized.
It would ease testing of existence, allow to free memory by setting varWithBigString := null (OK, I can use VarSetCapacity), to remove a table entry by setting it to nil/null (but we don't have associative arrays yet, so this remark is a foreview of this feature...).
But it will go in the other direction, requiring to initialize a var before using it, ie. var := var . val or var++ will throw errors if uninitialized...
At least, it would be consistent.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

Not only non-existant variables but also empty variables:

I agree, I forgot this, but it seemed like something that goes along the way.

Although I find the requested behavior more intuitive, I find bad practice to add up uninitialized variables...

This is not acceptable thinking in AHK coordinating system, apperently. We don't have even variable types, arrays or anything higher level, why would we have to be concerned about this.

The truth is that if AHK syntax already get me used to use variables without declaring them, I strongly urge this to be added to the languge as natural by its syntax as I don't want to have bunch of special cases around, witch as I learn AHK appears more and more...


Just to note it, C# does report an error for using uninitialised variables. I also like you must explicitely specify ref and out in eatch function call. Out is used so u don't have to initialise variables that are going to get value inside the function.
bool bOK;
XLS_SetSheetOrder(excelSheets, [color=olive]out[/color] bOK);

Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
I don't like the idea of making undefined or empty variables to behave in expressions as 0. If you use them in multiplication, like x = 5; ..x*y.. an empty y should behave as 1. And what do you want to do if y is not numeric? Treating non-number strings as empty is the consistent behavior, and an empty variable is non-numeric.

As PhiLho said, it is bad practice to use un-initialized variables in expressions (unless you know what you are doing). If someone takes your code w/o #NoEnv, he could have unpleasant surprises with environment variables, or just with a prior use of the variable. We should not promote this sloppy programming practice.

If you really want to save the explicit initialization, use a single line function or the expression
x Chr(!x*48)
instead of x. This works in hex mode, too, with any empty or numeric x value.

The "mambo jumbo" code works, too, but it is of double length, and returns 0 for non-numeric strings. It is often not desirable. VarExists(y)*y does not even work.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

x Chr(!x*48)

AHK is slow (as interpreter), multiplication is slow, there is also 1 function call and one concatenation. So, if I want just to make sure my variable is not going to be uninitialised I have to perform 4 operations one to be multiplication. Not right, if I am concerned, for such trivial thing....

I like the solution though for non repetitive calculations, but that just introduce a limitation.

As PhiLho said, it is bad practice to use un-initialized variables in expressions

As I said to PhiLho, this is not acceptable thinking in AHK coordinating system witch is oriented toward simplicity and the least amount of code possible.


If there are others who think like Laszlo maybe new directive should be introduced so we all be happy.

#InitVars [value]        - initialise non existent and empty vars in expressions to [color=red]value[/color]. Default is 0.

I think that initialisation of non numeric variables should be skipped for the sake of performance as AHK will have to check the contenst to determine that, and cuz it is cool to have some mechanism to announce that you are trying to do something strange, like adding numbers and strings. In this case old behavior should be kept.
Posted Image

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Concerning the idea of adding a null/nil value, I'm not currently in favor of it because I think it would add more complexity than it's worth. A blank value (empty string) seems like a suitable alternative in most cases (however, contrary opinions are welcome, especially if accompanied by compelling examples).

As for the main point of this topic, I agree that changing the policy for v2 is worth considering. When I designed expressions, it seemed inappropriate to treat empty strings as zero in math expressions because it would allow bugs caused by unintentionally uninitialized variables to go undetected. In other words, yielding a blank value seemed a good aid to debugging, at least in some cases.

However, I realized then and even more now that this policy is inconvenient -- possibly so much so that changing it for v2 would be worthwhile in spite of the compatibility problems.

To help decide, I've added a poll to this topic. Does anyone know offhand how PHP and other weakly-typed languages handle empty strings and unitialized variables in math expressions?

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
But what about the directive ????
It can solve the problems you mention ....

Why you didn't add it to the poll ?
Posted Image

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005

Does anyone know offhand how PHP and other weakly-typed languages handle empty strings and unitialized variables in math expressions?

Good question, although they don't necessarily target the same audience...
[color=violet]JavaScript (Firefox 1.5)[/color]

c = '';
a = 5 + 3;  // OK, 8
a = 5 + b;  // "b is not defined"
a = 5 + (typeof(b) == "undefined" ? 0 : b);  // OK, 5
a = "5" + "x";  // OK, "5x"
a = "5" + b;  // "b is not defined"
a = "5" + (typeof(b) == "undefined" ? "" : b);  // OK, "5"
a = 5 + c;  // OK, 5
a = 5 * c;  // OK, 0
alert(a);

// typeof is in recent versions of JS
[color=violet]JScript (WSH 5.6)[/color]

c = '';
a = 5 + 3;  // OK, 8
a = 5 + b;  // "Erreur d'exécution Microsoft JScript: 'b' est indéfini."
a = 5 + (typeof(b) == "undefined" ? 0 : b);  // OK, 5
a = "5" + "x";  // OK, "5x"
a = "5" + b;  // "Erreur d'exécution Microsoft JScript: 'b' est indéfini."
a = "5" + (typeof(b) == "undefined" ? "" : b);  // OK, "5"
a = "5" + c;  // OK, 5
a = "5" * c;  // OK, 0
WScript.StdOut.Write(a);
[color=violet]VBScript (WSH 5.6)[/color]

c = ""
a = 5 + 3  ' OK, 8
a = 5 + b  ' OK, 5
a = "5" + "x"  ' OK, "5x"
a = "5" + b  ' OK, "5"
a = 5 * b  ' OK, 0
a = 5 + c  ' "Type incompatible: 'c'"
a = 5 * c  ' "Type incompatible: 'c'"
WScript.Echo a
[color=violet]PHP 4.3.10[/color]

<?php
$c = '';
$a = 5 + 3;  // OK, 8
$a = 5 + b;  // OK with warning, 5: "Notice: Use of undefined constant b - assumed 'b' in test.php on line 3"
$a = 5 + $b;  // OK with warning, 5: "Notice: Undefined variable: b in test.php on line 4"
$a = "5" . "x";  // OK, "5x"
$a = "5" . $b;  // OK with warning, "5": "Notice: Undefined variable: b in test.php on line 6"
$a = "5" . b;  // OK with warning, "5b": "Notice: Use of undefined constant b - assumed 'b' in test.php on line 7"
$a = 5 * $b;  // OK with warning, 0: "Notice: Undefined variable: b in test.php on line 8"
$a = 5 * b;  // OK with warning, 0: "Notice: Use of undefined constant b - assumed 'b' in test.php on line 9"
$a = 5 + $c;  // OK, 5
$a = 5 * $c;  // OK, 0
echo $a;

// I think that these warnings can be disabled in php.ini
?>
[color=violet]Perl 5.8.7[/color]

# Default
$c = "";
$a = 5 + 3;  # OK, 8
$a = 5 + b;  # OK, 5
$a = 5 + $b;  # OK, 5
$a = "5" . "x";  # OK, "5x"
$a = "5" . $b;  # OK, "5"
$a = "5" . b;  # OK, "5b"
$a = 5 * $b;  # OK, 0
$a = 5 * b;  # OK, 0
$a = 5 + $c;  # OK, 5
$a = 5 * $c;  # OK, 0
print $a;

# With warnings:
use warnings;
$c = "";
$a = 5 + 3;  # OK, 8
$a = 5 + b;  # OK with warning, 5: "Argument "b" isn't numeric in addition (+) at Test.pl line 7."
$a = 5 + $b;  # OK with warning, 5: "Use of uninitialized value in addition (+) at Test.pl line 8."
$a = "5" . "x";  # OK, "5x"
$a = "5" . $b;  # OK with warning, "5": "Use of uninitialized value in concatenation (.) or string at Test.pl line 10."
$a = "5" . b;  # OK, "5b"
$a = 5 * $b;  # OK with warning, 0: "Use of uninitialized value in multiplication (*) at Test.pl line 12."
$a = 5 * b;  # OK with warning, 0: "Argument "b" isn't numeric in multiplication (*) at Test.pl line 13."
$a = 5 + $c;  # OK with warning, 5: "Argument "" isn't numeric in addition (+) at Test.pl line 14."
$a = 5 * $c;  # OK with warning, 0: "Argument "" isn't numeric in multiplication (*) at Test.pl line 15."
print $a;

# In strict mode:
use strict;
my $c = "";
$a = 5 + 3;  # OK, 8
$a = 5 + b;  # "Bareword "b" not allowed while "strict subs" in use at E:\Dev\Test.pl line 8."
$a = 5 + $b;  # OK, 5
$a = "5" . "x";  # OK, "5x"
$a = "5" . $b;  # OK, "5"
$a = "5" . b;  # "Bareword "b" not allowed while "strict subs" in use at E:\Dev\Test.pl line 8."
$a = 5 * $b;  # OK, 0
$a = 5 + $c;  # OK, 5
$a = 5 * $c;  # OK, 0
print $a;

# We can combine strict and warnings.
[color=violet]Lua 5.0[/color]

c = ''
a = 5 + 3  -- OK, 8
a = 5 + b  -- "attempt to perform arithmetic on global `b' (a nil value)"
a = 5 + (b or 0)  -- OK, 5
a = "5" .. "x"  -- OK, "5x"
a = "5" .. b  -- attempt to concatenate global `b' (a nil value)
a = "5" .. (b or "")  -- OK, "5"
a = 5 + c  -- attempt to perform arithmetic on global `c' (a string value)
a = 5 * c  -- attempt to perform arithmetic on global `c' (a string value)
print(a)

-- I show the classical way to handle undefined variables, using or, since nil tests as false
As you can see, there is no "universal" rule. We can have a default permissive behavior (Perl, VBS), permissive with warnings (PHP) or a more strict behavior (others). In Perl, we can have a more strict behavior, great for debugging. In most languages, there is a workaround for this problem, based on ? : operator or equivalent.

[EDIT] Added empty string test cases.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
As I said, directive would be perfect. Keep the old behavior and change it if you want with directive #InitVars. So we can have both .

Also, I see the rule: newbee oriented languages tend to intialise with 0 more serious languages tend to report errors or warnings. Thats why VBScript has it that way and Perl as it is used as CGI language mostly also permits this for the sake of shorter code. Sounds to me like AHK fall into this category...
Posted Image

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

Keep the old behavior and change it with if you want with directive #InitVars. So we can have both .


I second it .. though I do not know how complex it would be to implement it..

BTW, I did not vote!

:)
kWo4Lk1.png

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
If there is nothing to vote for, you should vote for closest to what you have at mind.

I don't see directive up there, but I still voted for the first one.
You should do the same.
Posted Image

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Thanks PhiLho. I also checked the following in PHP:
$a = ""; // Init to explicit empty string.
5 + $a -> Yields 5 without warning.
5 * $a -> Yields 0 without warning.
5 / $a -> Yields "" and gives warning "Division by zero".

Concerning the idea of adding a directive to choose the behavior, I don't like it because:

1) It reduces the ability to copy & paste code from one script to another. In other words, if a function or subroutine relies on the directive being turned on, it wouldn't work when pasted into another script whose author wants it kept turned off.

2) It reduces the ability to collaborate on a project when one author is used to writing functions with the directive On and the other with it Off. You might say, "they can just turn it on and off in their individual functions/include-files, then paste them together". But it just seems wrong to encourage a split in scripting habits by providing the directive in the first place.

3) It complicates the language because arguably, there are already too many directives.

So in general, I don't like language-altering directives (and in hindsight, directives like #EscapeChar may have been a bad idea; but because they're so rarely used, it doesn't matter much).

Thanks.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

If there is nothing to vote for, you should vote for closest to what you have at mind.


None of them is closer.. I would have voted only for Other!

As a beginner, I was very surprised and pleased with AutoHotkey for not irritating me with error messages for uninitialised variables. Now being a bit experienced with AutoHotkey does not mean I have to change my opinion.

I stay pleased, even If 5 + y returns me null!

When I designed expressions, it seemed inappropriate to treat empty strings as zero in math expressions because it would allow bugs caused by unintentionally uninitialized variables to go undetected. In other words, yielding a blank value seemed a good aid to debugging, at least in some cases.


Chris knows better & I respect his judgement!

:)
kWo4Lk1.png