Writing Access functions

N

new2access123

I am an old FoxPro programmer (but have been out of programming for many
years) and I have been through the Access basics that I have been able to
find on line. So I can create tables, forms enter data the basics. I am
learning VBA no problem there. Now I want to write some functions. I would
like to write one function that is passed an ID and returns the last name of
the person having that ID. I would like to write this function in two ways:

1. Connect to a table in my DB find the ID and return the name
2. Have the function perform a query that returns a record set from which the
name is returned.

Does any one know where I can find some straight forward simple examples
demonstrating this?

This is a training exercise for me to learn how to:
* Connect to tables and process data
* Create a record set and process data from the recordset
* Use debugging techniques breakpoints, run code from the immediate window
etc.

I would really appreciate the help

Thanks
 
D

DrGUI

The following gets you the LastName using the DLookup function in Access
(verfsus performing a query)


public function GetUserName (iUserID as integer) as string

dim strLastName as string
strLastName = ""
strLastName = dlookup("LastName","tbl_Users","userID = " & iUserID)
GetUserName = strLastName

end function

To do the same thing using a query, try the following:

public function GetUserName (iUserID as integer) as string

dim strLastName as string
dim rs as new ADODB.recordset
dim strSQL as string

strSQL = "select LastName from tbl_Users where userID = " & iUserID
rs.open strSQL, currentproject.connection
if not (rs.bof and rs.eof) then
strLastName = rs("LastName")
else
strLastName = ""
endif

rs.close
set rs=nothing

GetUserName = strLastName

end function
 
A

Allen Browne

Here's an example to pull apart and see how it works:
http://allenbrowne.com/ser-42.html

The function in that page takes these arguments:
- Expr = the name of the field you want to look up;
- Domain = the name of the table/query to look in;
- Criteria = a WHERE clause for what to match;
- OrderClause = how to sort the records if are multiple matches.

You can omit the last one (it's optional), so to lookup the Surname field of
the Clients table where the ClientID field is 99, you would use:
= ELookup("Surname", "Clients", "ClientID = 99")

The code illustrates how to open a recordset with as few fields and records
as possible (quickest, and least memory used.) It then checks to see if the
field returned is a multi-valued field (which needs special handling), and
returns the result.

For a more basic example of working with a recordset, see:
http://allenbrowne.com/func-DAO.html#DAORecordsetExample

BTW, the built-in DLookup() can do this too:
http://allenbrowne.com/casu-07.html
 
J

John W. Vinson

I am an old FoxPro programmer (but have been out of programming for many
years) and I have been through the Access basics that I have been able to
find on line. So I can create tables, forms enter data the basics. I am
learning VBA no problem there. Now I want to write some functions. I would
like to write one function that is passed an ID and returns the last name of
the person having that ID. I would like to write this function in two ways:

1. Connect to a table in my DB find the ID and return the name
2. Have the function perform a query that returns a record set from which the
name is returned.

Does any one know where I can find some straight forward simple examples
demonstrating this?

This is a training exercise for me to learn how to:
* Connect to tables and process data
* Create a record set and process data from the recordset
* Use debugging techniques breakpoints, run code from the immediate window
etc.

I would really appreciate the help

Thanks

Don't reinvent wheels!

Look at the VBA help for "DLookUp". It does exactly what you describe for
either tables or queries.
 
N

new2access123 via AccessMonster.com

Thanks. This is just what I needed. I am just learning VBA and this is a
training/learning exercise for me.
The following gets you the LastName using the DLookup function in Access
(verfsus performing a query)

public function GetUserName (iUserID as integer) as string

dim strLastName as string
strLastName = ""
strLastName = dlookup("LastName","tbl_Users","userID = " & iUserID)
GetUserName = strLastName

end function

To do the same thing using a query, try the following:

public function GetUserName (iUserID as integer) as string

dim strLastName as string
dim rs as new ADODB.recordset
dim strSQL as string

strSQL = "select LastName from tbl_Users where userID = " & iUserID
rs.open strSQL, currentproject.connection
if not (rs.bof and rs.eof) then
strLastName = rs("LastName")
else
strLastName = ""
endif

rs.close
set rs=nothing

GetUserName = strLastName

end function
I am an old FoxPro programmer (but have been out of programming for many
years) and I have been through the Access basics that I have been able to
[quoted text clipped - 21 lines]
 
N

new2access123 via AccessMonster.com

Thanks for the references. I'll spend some time studying them.

Allen said:
Here's an example to pull apart and see how it works:
http://allenbrowne.com/ser-42.html

The function in that page takes these arguments:
- Expr = the name of the field you want to look up;
- Domain = the name of the table/query to look in;
- Criteria = a WHERE clause for what to match;
- OrderClause = how to sort the records if are multiple matches.

You can omit the last one (it's optional), so to lookup the Surname field of
the Clients table where the ClientID field is 99, you would use:
= ELookup("Surname", "Clients", "ClientID = 99")

The code illustrates how to open a recordset with as few fields and records
as possible (quickest, and least memory used.) It then checks to see if the
field returned is a multi-valued field (which needs special handling), and
returns the result.

For a more basic example of working with a recordset, see:
http://allenbrowne.com/func-DAO.html#DAORecordsetExample

BTW, the built-in DLookup() can do this too:
http://allenbrowne.com/casu-07.html
I am an old FoxPro programmer (but have been out of programming for many
years) and I have been through the Access basics that I have been able to
[quoted text clipped - 23 lines]
 
N

new2access123 via AccessMonster.com

Thank you for the input. I was not aware of DLookUp. That will do the job I
described. And I will use it. Looking up DLookUp has exposed a wealth of
functions that are available. Being brand new to ABA my objective was to get
some code to do a common task to learn structure, commands and syntax.
I am an old FoxPro programmer (but have been out of programming for many
years) and I have been through the Access basics that I have been able to
[quoted text clipped - 19 lines]

Don't reinvent wheels!

Look at the VBA help for "DLookUp". It does exactly what you describe for
either tables or queries.
 
J

John W. Vinson

Thank you for the input. I was not aware of DLookUp. That will do the job I
described. And I will use it. Looking up DLookUp has exposed a wealth of
functions that are available. Being brand new to ABA my objective was to get
some code to do a common task to learn structure, commands and syntax.

Yep - there's a lot of stuff there, and the Help file ranges from perplexing
to abominable, I fear! Don't hesitate to ask here, and there are some other
learning resources available; you've gotten some, here are some more:

Jeff Conrad's resources page:
http://www.accessmvp.com/JConrad/accessjunkie/resources.html

The Access Web resources page:
http://www.mvps.org/access/resources/index.html

Roger Carlson's tutorials, samples and tips:
http://www.rogersaccesslibrary.com/

A free tutorial written by Crystal:
http://allenbrowne.com/casu-22.html

A video how-to series by Crystal:
http://www.YouTube.com/user/LearnAccessByCrystal

MVP Allen Browne's tutorials:
http://allenbrowne.com/links.html#Tutorials
 
D

David W. Fenton

dim rs as new ADODB.recordset

Helping someone learn Access using ADO is really inadvisable. ADO is
no longer a default reference (and it never should have been), so
you're providing code that's going to break for most users of recent
versions of Access.
 
D

David W. Fenton

I was not aware of DLookUp. That will do the job I
described. And I will use it. Looking up DLookUp has exposed a
wealth of functions that are available. Being brand new to ABA my
objective was to get some code to do a common task to learn
structure, commands and syntax.

Have a look at this:

http://easyweb.easynet.co.uk/trevor/downloads/baslookup.zip

That's from the era in which the domain lookup functions (DCount(),
DLookup(), DMax(), DMin()) were slower on linked tables than on
local tables. Trevor Best wrote replacements for them that worked
exactly the same but were not slow. He later enhanced them to have
additional features, and I've enhanced my own versions of them.

The point is that these are code examples of functions that work
like what you described and can help you learn how to write your own
functions.
 
D

David W. Fenton

new2access123 said:
This is a training exercise for me to learn how to:
* Connect to tables and process data
* Create a record set and process data from the recordset
* Use debugging techniques breakpoints, run code from the
immediate window etc.

I would really appreciate the help

Here is what I consider some important advice for writing
functions/subs:

1. don't create a function unless you want to return a value.
Otherwise, create a sub. This is contrary to Allen Browne's advice
-- he says to create everything as a function, but I find that
confusing, as a function that returns nothing looks to me like a
design error (it actually does return something, a Null variant,
which is pretty useful).

2. strongly type the input parameters and the output value. Do this:

Public Function NameFromID(lngPersonID As Long) As String

Don't do this:

Public Function NameFromID(lngPersonID)

By default, a variable without a data type defined is a Variant.
Variants are extremely valuable in certain contexts, but when you
are always passing the same value and don't want to accept a Null
(in this case you'd be passing a PK, which can never be Null, so
there's no utility in using Variant data type for it).

Likewise, a function with an undefined return type returns a
Variant, and if you read the help file on the Variant data type,
you'll see that it's very complicated (because Variants have
sub-types that you can't really control -- they are assigned
implicitly by VBA), and you should avoid it using it except
completely intentionally.

3. some people use the same naming conventions for functions that
they use for their variables, e.g., Leszynski/Reddick, or Hungarian
notation. So, a function returning a Long Integer would be named
starting with "lng", and a string function with "str". I have done
this sometimes, but I find that it makes using Intellisense more
complicated, as you then have to type "str" before you get to a
possible match.

4. on all coding, be sure you choose your scope appropriately. Any
function in a standalone module is public by default, but I think
it's best to be completely explicit about this. In a standalone
module, this is public:

Function NameFromID(lngPersonID As Long) As String

It's also public by default in a class module attached to a form or
report. In a standalone module, that's likely what you want, but in
a form or report, it's fairly unusual to have a public function.

It's best to always specify scope:

Public Function NameFromID(lngPersonID As Long) As String

....is for all the functions you want visible outside the module
where it's defined, and:

Private Function NameFromID(lngPersonID As Long) As String

....is for all functions you want private to the specific module
where they are defined. My default for standalone modules is Public
and for form/report modules Private.

5. it's a good idea to understand passing values By Value and By
Reference. By default, VBA passes By Reference. This means that a
pointer to the memory location where the variable/object being
passed is stored is handed off to the function/sub you're calling.

Public Function NameFromID(lngPersonID As Long) As String

....is equivalent to:

Public Function NameFromID(ByRef lngPersonID As Long) As String

.... what it means when you call it:

Dim strName As String

strName = NameFromID(Me!PersonID)

....is that a pointer to the memory location of Me!PersonID is
passed. If you pass a control reference:

strName = NameFromID(Me!cmbPerson)

....an implicit reference to the cmbPerson combo box is created and
passed. This can lead to problems that are very difficult to
troubleshoot. So, basically, you should try to use ByRef only when
you really need it. Those situations would be:

1. when you really want to pass an object:

Public Function ShowHideControls(ByRef col As Collection, _
bolVisible As Boolean) As Boolean
Dim ctl As Control

For Each ctl In col
ctl.Visible = bolVisible
Next ctl
Set ctl = Nothing

ShowHideControls = True
End Function

You'd use that thus:

If Not ShowHideControls(Me.Controls, True) Then
MsgBox ("Something went wrong showing/hiding controls!")
End If

The reason you pass By Reference is because you want to operate on
the thing that you've passed within the function/sub itself.

This applies to simple variables and is a useful technique when you
want to return multiple values:

Public Sub GetFormColors(ByRef lngBackground As Long, _
ByRef lngLabel As Long, ByRef lngControlBackground As Long, _
ByRef lngControlText As Long)
lngBackground = -2147483633 ' system color
lngLabel = 0 ' black
lngControlBackground = 16777215 ' white
lngControlText = 0 ' black
End Sub

When you call it, you'd do something like this:

Dim lngFormBackground As Long
Dim lngLabelColor As Long
Dim lngTextBoxBackground As Long
Dim lngTextBoxForeground As Long
Dim ctl As Control

Call GetFormColors(lngFormBackground, lngLabelColor, _
lngTextBoxBackground, lngTextBoxForeground)
Me.Section(0).Background = lngFormBackground
For Each ctl In Me.Controls
Select Case ctl.ControlType
Case acLabel
ctl.ForeColor = lngLabelColor
Case acTextBox, acComboBox, acListBox
ctl.BackColor = lngTextBoxBackground
ctl.ForeColor = lngTextBoxForeground
End Select
Next ctl
Set ctl = Nothing

What you've done is make one call to the subroutine, passing your
local variables, which get values assigned to them that are then
usable after the subroutine has finished.

I often use a function for code that executes a SQL
update/insert/delete, and have the function return the
RecordsAffected value (i.e., how many records were
updated/inserted/deleted). However, I also frequently pass a
variable for the same value so I can use it in code differently:

Public Function SetPersonUpdated(dteDate As Date, _
lngUpdateCount As Long) As Long
On Error GoTo errHandler
Dim db As DAO.Database
Dim strSQL As String

Set db = CurrentDB
strSQL = "UPDATE tblPerson SET tblPerson.Updated = #"
strSQL = strSQL & _
DateSerial(Day(dteDate), Month(dteDate), Year(dteDate)
strSQL = strSQL & "#;"
db.Execute strSQL, dbFailOnError
lngUpdateCount = db.RecordsAffected
SetPersonUpdated = lngUpdateCount

exitRoutine:
Set db = Nothing
Exit Function

errHandler:
MsgBox(Err.Number & ": " & Err.Description, vbExclamation, _
"Error in SetPersonUpdated()"
Resume exitRoutine
End Function

Now, this is not the best example here, as the function returns the
same value as the passed in variable, but if the function returns
something different, it allows you to get something else from the
internals of the function/sub (all of this about ByRef/ByVal applies
to both functions and subs).

Now, where to use ByVal? Well, any time you're operating on the
value from a control, you should pass ByVal. Take the example I
started with:

Public Function NameFromID(lngPersonID As Long) As String

If you do this:

Me!txtLastName = NameFromID(Me!cmbPerson)

....then you're passiong the CONTROL to the function, and that
implicit control reference can cause problems. You aren't going to
be operating on the *control* itself, but on the value that control
returns. Here are couple of ways to avoid the implicit reference
with the ByRef parameter:

Me!txtLastName = NameFromID(Me!cmbPerson.Value)
Me!txtLastName = NameFromID((Me!cmbPerson))

Even though the default property of a control is .Value, when you
pass a control to a function where the parameter is defined ByRef
(implicitly or explicitly), you'll be passing a reference to the
control. By explicitly specifying the .Value, you're avoiding that.
The parens do the same thing, forcing evaluation of the value of the
control before it's passed to the function.

But you can avoid needing to do either of those by simply defining
your parameter as ByVal:

Public Function NameFromID(ByVal lngPersonID As Long) As String

That takes care of any problems, and it's really what you want,
anyway.

I was going to go on about using static variables and functions with
no parameters, but I think I've already said too much!
 
N

new2access123 via AccessMonster.com

Thanks for the additional resources. I am checking them out. You are
correct about the Help and much of the other documentation out there. It is
pretty poor. Lots on how to use Access but no real how-to explaining here's
how you write a VBA app to interact with your data. But with the information
I have gotten here I am getting it together.

I'll be back with more questions…
 
N

new2access123 via AccessMonster.com

The ziped file is a .bas? I do not know how to open it.
 
N

new2access123 via AccessMonster.com

Great points! I am with you 100%. And thank you for the refresher on
passing values by Value or by Reference. It makes a big difference as I am
now recalling from my FoxPro and C# days. Your explanation and code are
concise and right on. It would have taken me forever to search out that info.


Feel free to go on with using static variables and functions with
no parameters. Post here or send directly to me. This is all good refresher
and VBA how-to that I need and am looking for.

Thank you

This is a training exercise for me to learn how to:
* Connect to tables and process data
[quoted text clipped - 3 lines]
I would really appreciate the help

Here is what I consider some important advice for writing
functions/subs:

1. don't create a function unless you want to return a value.
Otherwise, create a sub. This is contrary to Allen Browne's advice
-- he says to create everything as a function, but I find that
confusing, as a function that returns nothing looks to me like a
design error (it actually does return something, a Null variant,
which is pretty useful).

2. strongly type the input parameters and the output value. Do this:

Public Function NameFromID(lngPersonID As Long) As String

Don't do this:

Public Function NameFromID(lngPersonID)

By default, a variable without a data type defined is a Variant.
Variants are extremely valuable in certain contexts, but when you
are always passing the same value and don't want to accept a Null
(in this case you'd be passing a PK, which can never be Null, so
there's no utility in using Variant data type for it).

Likewise, a function with an undefined return type returns a
Variant, and if you read the help file on the Variant data type,
you'll see that it's very complicated (because Variants have
sub-types that you can't really control -- they are assigned
implicitly by VBA), and you should avoid it using it except
completely intentionally.

3. some people use the same naming conventions for functions that
they use for their variables, e.g., Leszynski/Reddick, or Hungarian
notation. So, a function returning a Long Integer would be named
starting with "lng", and a string function with "str". I have done
this sometimes, but I find that it makes using Intellisense more
complicated, as you then have to type "str" before you get to a
possible match.

4. on all coding, be sure you choose your scope appropriately. Any
function in a standalone module is public by default, but I think
it's best to be completely explicit about this. In a standalone
module, this is public:

Function NameFromID(lngPersonID As Long) As String

It's also public by default in a class module attached to a form or
report. In a standalone module, that's likely what you want, but in
a form or report, it's fairly unusual to have a public function.

It's best to always specify scope:

Public Function NameFromID(lngPersonID As Long) As String

...is for all the functions you want visible outside the module
where it's defined, and:

Private Function NameFromID(lngPersonID As Long) As String

...is for all functions you want private to the specific module
where they are defined. My default for standalone modules is Public
and for form/report modules Private.

5. it's a good idea to understand passing values By Value and By
Reference. By default, VBA passes By Reference. This means that a
pointer to the memory location where the variable/object being
passed is stored is handed off to the function/sub you're calling.

Public Function NameFromID(lngPersonID As Long) As String

...is equivalent to:

Public Function NameFromID(ByRef lngPersonID As Long) As String

... what it means when you call it:

Dim strName As String

strName = NameFromID(Me!PersonID)

...is that a pointer to the memory location of Me!PersonID is
passed. If you pass a control reference:

strName = NameFromID(Me!cmbPerson)

...an implicit reference to the cmbPerson combo box is created and
passed. This can lead to problems that are very difficult to
troubleshoot. So, basically, you should try to use ByRef only when
you really need it. Those situations would be:

1. when you really want to pass an object:

Public Function ShowHideControls(ByRef col As Collection, _
bolVisible As Boolean) As Boolean
Dim ctl As Control

For Each ctl In col
ctl.Visible = bolVisible
Next ctl
Set ctl = Nothing

ShowHideControls = True
End Function

You'd use that thus:

If Not ShowHideControls(Me.Controls, True) Then
MsgBox ("Something went wrong showing/hiding controls!")
End If

The reason you pass By Reference is because you want to operate on
the thing that you've passed within the function/sub itself.

This applies to simple variables and is a useful technique when you
want to return multiple values:

Public Sub GetFormColors(ByRef lngBackground As Long, _
ByRef lngLabel As Long, ByRef lngControlBackground As Long, _
ByRef lngControlText As Long)
lngBackground = -2147483633 ' system color
lngLabel = 0 ' black
lngControlBackground = 16777215 ' white
lngControlText = 0 ' black
End Sub

When you call it, you'd do something like this:

Dim lngFormBackground As Long
Dim lngLabelColor As Long
Dim lngTextBoxBackground As Long
Dim lngTextBoxForeground As Long
Dim ctl As Control

Call GetFormColors(lngFormBackground, lngLabelColor, _
lngTextBoxBackground, lngTextBoxForeground)
Me.Section(0).Background = lngFormBackground
For Each ctl In Me.Controls
Select Case ctl.ControlType
Case acLabel
ctl.ForeColor = lngLabelColor
Case acTextBox, acComboBox, acListBox
ctl.BackColor = lngTextBoxBackground
ctl.ForeColor = lngTextBoxForeground
End Select
Next ctl
Set ctl = Nothing

What you've done is make one call to the subroutine, passing your
local variables, which get values assigned to them that are then
usable after the subroutine has finished.

I often use a function for code that executes a SQL
update/insert/delete, and have the function return the
RecordsAffected value (i.e., how many records were
updated/inserted/deleted). However, I also frequently pass a
variable for the same value so I can use it in code differently:

Public Function SetPersonUpdated(dteDate As Date, _
lngUpdateCount As Long) As Long
On Error GoTo errHandler
Dim db As DAO.Database
Dim strSQL As String

Set db = CurrentDB
strSQL = "UPDATE tblPerson SET tblPerson.Updated = #"
strSQL = strSQL & _
DateSerial(Day(dteDate), Month(dteDate), Year(dteDate)
strSQL = strSQL & "#;"
db.Execute strSQL, dbFailOnError
lngUpdateCount = db.RecordsAffected
SetPersonUpdated = lngUpdateCount

exitRoutine:
Set db = Nothing
Exit Function

errHandler:
MsgBox(Err.Number & ": " & Err.Description, vbExclamation, _
"Error in SetPersonUpdated()"
Resume exitRoutine
End Function

Now, this is not the best example here, as the function returns the
same value as the passed in variable, but if the function returns
something different, it allows you to get something else from the
internals of the function/sub (all of this about ByRef/ByVal applies
to both functions and subs).

Now, where to use ByVal? Well, any time you're operating on the
value from a control, you should pass ByVal. Take the example I
started with:

Public Function NameFromID(lngPersonID As Long) As String

If you do this:

Me!txtLastName = NameFromID(Me!cmbPerson)

...then you're passiong the CONTROL to the function, and that
implicit control reference can cause problems. You aren't going to
be operating on the *control* itself, but on the value that control
returns. Here are couple of ways to avoid the implicit reference
with the ByRef parameter:

Me!txtLastName = NameFromID(Me!cmbPerson.Value)
Me!txtLastName = NameFromID((Me!cmbPerson))

Even though the default property of a control is .Value, when you
pass a control to a function where the parameter is defined ByRef
(implicitly or explicitly), you'll be passing a reference to the
control. By explicitly specifying the .Value, you're avoiding that.
The parens do the same thing, forcing evaluation of the value of the
control before it's passed to the function.

But you can avoid needing to do either of those by simply defining
your parameter as ByVal:

Public Function NameFromID(ByVal lngPersonID As Long) As String

That takes care of any problems, and it's really what you want,
anyway.

I was going to go on about using static variables and functions with
no parameters, but I think I've already said too much!
 
J

Jack Leach

1. don't create a function unless you want to return a value.
Otherwise, create a sub. This is contrary to Allen Browne's advice
-- he says to create everything as a function, but I find that
confusing, as a function that returns nothing looks to me like a
design error (it actually does return something, a Null variant,
which is pretty useful).

Just as a side note to OP, there is one significant advantage to using a
Function over a Sub (assuming you understand the Null variant it may return
without a value applied)... When working elsewhere besides VBA, Public Subs
are not callable.

For instance, SQL strings, Conditional Formatting, Menu/Toolbar commands,
Control sources, Macros (thought the only one you should be using is the
Autoexec macro) etc etc. These "Access-side" utilization of code will only
work with functions (or properties, if you want to go there). You cannot
reference Subs this way.



--
Jack Leach
www.tristatemachine.com

"I haven''t failed, I''ve found ten thousand ways that don''t work."
-Thomas Edison (1847-1931)
 
N

new2access123 via AccessMonster.com

Thanks for the clarification. I will make note of that for future reference.

Jack said:
1. don't create a function unless you want to return a value.
Otherwise, create a sub. This is contrary to Allen Browne's advice
-- he says to create everything as a function, but I find that
confusing, as a function that returns nothing looks to me like a
design error (it actually does return something, a Null variant,
which is pretty useful).

Just as a side note to OP, there is one significant advantage to using a
Function over a Sub (assuming you understand the Null variant it may return
without a value applied)... When working elsewhere besides VBA, Public Subs
are not callable.

For instance, SQL strings, Conditional Formatting, Menu/Toolbar commands,
Control sources, Macros (thought the only one you should be using is the
Autoexec macro) etc etc. These "Access-side" utilization of code will only
work with functions (or properties, if you want to go there). You cannot
reference Subs this way.
[quoted text clipped - 228 lines]
I was going to go on about using static variables and functions with
no parameters, but I think I've already said too much!
 
D

David W. Fenton

You are
correct about the Help and much of the other documentation out
there. It is pretty poor. Lots on how to use Access but no real
how-to explaining here's how you write a VBA app to interact with
your data.

I disagree that the help and documentation is poor. Your goal should
be to create as much of your application without a single line of
VBA code by using the tools that Access provides you interactively.
Only when you exhaust the capabilities of interactive Access should
you start writing code.
 
A

Allen Browne

David W. Fenton said:
1. don't create a function unless you want to return a value.
Otherwise, create a sub. This is contrary to Allen Browne's advice
-- he says to create everything as a function, but I find that
confusing, as a function that returns nothing looks to me like a
design error (it actually does return something, a Null variant, ...

Actually, I think it returns Empty rather than Null, David.

Perhaps that proves your point that it's somewhat confusing. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top