Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Testing for missing parameters in a function.

898 views
Skip to first unread message

Joel Jaykul Bennett

unread,
Oct 23, 2007, 2:01:46 PM10/23/07
to
Can anyone explain a way around this behavior?
Here's a sample function. It works exactly the way I expected it to:

[1]> function test-null { param($one=$null,$two=$null); if($one -eq
$null){ "One is Null" } if($two -eq $null){ "Two is Null"}}
[2]> test-null
One is Null
Two is Null


However, if we decide that we want to make this type-safe, the
behavior changes:

[3]> function test-null { param([string]$one=$null,[string]$two=
$null); if($one -eq $null){ "One is Null" } if($two -eq $null){ "Two
is Null"}}
[4]> test-null
[5]> test-null $null $null
[6]>

Suddenly, -eq $null returns false, even when you explicitly set the
parameter to $null ... I thought to try -like, since it seems to get
me out of these sorts of problems occasionally, and that works, except
that it tests an empty string as -eq $null:

[7]> function test-null { param([string]$one=$null,[string]$two=
$null); if($one -like $null){ "One is Null" } if($two -
like $null){ "Two is Null"}}
[8]> test-null
One is Null
Two is Null
[9]> test-null $null $null
One is Null
Two is Null
[10]> test-null "" ""
One is Null
Two is Null
[11]> test-null " " " "
[12]>

The problem is apparently that once you type something as string, you
can't ever set it to $null again:

[13]> $foo = "A string"
[14]> $foo -eq $null
False
[15]> $foo = ""
[16]> $foo -eq $null
False
[17]> $foo = $null
[18]> $foo -eq $null
True
[19]> [string]$foo = "A string"
[20]> $foo -eq $null
False
[21]> $foo = $null
[22]> $foo -eq $null
False
[23]>


So, is there a way to tell the difference between a string that wasn't
set, and one which was set to an empty string? I mean, I came up with
the idea of setting the default to something outrageous (ie: something
nobody would pass in, like the distinctly extended ascii "ÞüÞ") and
then testing for that, instead of for null ... but really, I mean,
there's got to be a better way, right? ...

Why can't I set a string = null?

Shay Levi

unread,
Oct 23, 2007, 2:25:33 PM10/23/07
to
You can check for the string's length property to see if some value passed,
or even use the throw statment to
ensure/enforce a value for $one.

param($one=$(throw "got to pass something"))


Shay
http://scriptolog.blogspot.com

Kiron

unread,
Oct 23, 2007, 2:32:54 PM10/23/07
to
You can negate the variable:

function test-null { param([string]$one=$null,[string]$two=$null); if(!$one){ "One is Null" } if(!$two){ "Two is Null"}}

--
Kiron

Kirk Munro

unread,
Oct 24, 2007, 5:29:48 PM10/24/07
to
Hi Joel,

This isn't the answer to your question, but I was curious about this so I
dug in a little to see what could be done. I was able to re-assign a
strongly-typed string variable to null, but I had to jump through a few
hoops to do it and I don't think it would work when trying to assign a
default value in a function. Here's the transcript:

PS C:\> [string]$foo = $null
PS C:\> $foo.GetType()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object

PS C:\> Get-Variable foo | fl *

Name : foo
Description :
Value :
Options : None
Attributes : {System.Management.Automation.ArgumentTypeConverterAttribute}

PS C:\> (Get-Variable foo).Attributes.Clear()
PS C:\> $foo = $null
PS C:\> $foo.GetType()
You cannot call a method on a null-valued expression.
At line:1 char:13
+ $foo.GetType( <<<< )
PS C:\> Get-Variable foo | fl *

Name : foo
Description :
Value :
Options : None
Attributes : {}

PS C:\> $foo -eq $null
True

So, if you want to distinguish between a non-strongly-typed string and a
strongly-typed string you could check the type using GetType() and check the
attributes to see if the
System.Management.Automation.ArgumentTypeConverterAttribute is set. But if
you're forcing the strings to be strongly typed in your function "header",
then I don't know what you could do other than test the values for null
first and after that test manually check the types and return an appropriate
error yourself if the type isn't correct.

Or, I just had a thought, you could do this instead:

function test {
param($first = $null)
if ($first -eq $null) {
"Param is NULL"
} else {
[string]$second = $first
if ($second.Length -eq 0) {
"Param is EMPTY"
}
}
}

Then if you ran through steps similar to what you did earlier, you get this:

PS C:\> test $null
Param is NULL
PS C:\> test ([string]$null)
Param is EMPTY
PS C:\> $foo = [string]$null
PS C:\> $bar = $null
PS C:\> test $foo
Param is EMPTY
PS C:\> test $bar
Param is NULL

This seems to be a better approach if your desire is to distinguish between
no value being passed in and a string value that is actually empty, and
afaik it is the only way to resolve your problem as I see it without using
the unique default value approach you mentioned in your post.

-
Kirk Munro
Poshoholic
http://poshoholic.com

"Joel Jaykul Bennett" <Jay...@gmail.com> wrote in message
news:1193162506....@i38g2000prf.googlegroups.com...

nobody would pass in, like the distinctly extended ascii "ήόή") and

Joel Jaykul Bennett

unread,
Oct 24, 2007, 6:37:19 PM10/24/07
to
Thanks guys ... looks like the best answer is probably to leave it not
type-enforced and be able to test it against null and explicitly cast
it to string. I don't like the fact that this means I'm failing to
advertise that I expect a string, but since PSh doesn't really give
people the function signature anyway, I guess it's not a big loss. :-)

0 new messages