473,394 Members | 1,813 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

Metacode (was "Custom error numbers/messages tip")

Here is some code to generate code for raising and getting information about
custom errors in an application. Executing the GenerateXyzErrDefs procedure
generates the code.

<tblXyzError>
ErrorCodeOffset (Long Int) ErrorObjBaseName (Text(50))
ErrorDescription (Text(255))

1 DontDoThat
Hey! Don't do that!

2 NotThatEither Woah!
Don't do that either!

3 AttemptedInstanceReinit
Attempted to reinitialize an instance of an object type that does not allow
multiple initializations per instance.

</tblXyzError>
<clsErrorDefinition>
Option Compare Database
Option Explicit

Private Const mycVBErrMethodNotApplicableInContxt = 444&

Private mlngErrNumber As Long
Private mstrErrDescrip As String

Public Property Get Number() As Long
Number = mlngErrNumber
End Property

Public Property Get Description() As String
Description = mstrErrDescrip
End Property

Public Sub Setup(ByVal lngErrNumber As Long, strDescription As String)
If mlngErrNumber <> 0 Then XyzErrAttemptedInstanceReinit.Raise
mlngErrNumber = lngErrNumber
mstrErrDescrip = strDescription
End Sub

Public Sub Raise()
Err.Raise Number, , Description
End Sub
</clsErrorDefinition>
<basXyzCodeGeneration>
Option Compare Database
Option Explicit

Private Const mycXyzErrDefModuleName = "basXyzErrorDefinitions"
Private Const mycXyzErrorTableName = "tblXyzError"
Private Const mycXyzObjPrefix = "xyz"
Public Const xyzcErrorCodeBase = 1000&

Public Sub GenerateXyzErrDefs()
Dim vbcsProject As VBIDE.VBComponents
Dim vbcModule As VBIDE.VBComponent
Dim db As DAO.Database
Dim rstXyzErrors As DAO.Recordset
Dim strNewFuncName As String
Dim lngErrorNum As Long

Set vbcsProject = VBE.VBProjects(1).VBComponents
RemoveVBComponentIfExists vbcsProject, mycXyzErrDefModuleName
Set vbcModule = CreateNewVBModule(vbcsProject, mycXyzErrDefModuleName)
vbcModule.Name = mycXyzErrDefModuleName

Set db = CurrentDb
Set rstXyzErrors = db.OpenRecordset( _
"SELECT * FROM [" & mycXyzErrorTableName & "] " & _
"ORDER BY ErrorCodeOffset", _
dbOpenDynaset, dbReadOnly)
If rstXyzErrors.RecordCount > 0 Then
While Not rstXyzErrors.EOF
strNewFuncName = _
UpperCaseFirstStringChar(mycXyzObjPrefix) & _
"Err" & rstXyzErrors!ErrorObjBaseName
lngErrorNum = xyzcErrorCodeBase + rstXyzErrors!ErrorCodeOffset
vbcModule.CodeModule.InsertLines _
vbcModule.CodeModule.CountOfLines + 1, _
"Public Function " & strNewFuncName & "() As clsErrorDefinition" & vbCrLf & _
" Static sobjErrDefinition As clsErrorDefinition" & vbCrLf & _
" If sobjErrDefinition Is Nothing Then" & vbCrLf & _
" Set sobjErrDefinition = New clsErrorDefinition" & vbCrLf & _
" sobjErrDefinition.Setup _" & vbCrLf & _
" " & lngErrorNum & ", _" & vbCrLf & _
" """ & rstXyzErrors!ErrorDescription & """" & vbCrLf & _
" End If" & vbCrLf & _
" Set " & strNewFuncName & " = sobjErrDefinition" & vbCrLf & _
"End Function"
rstXyzErrors.MoveNext
Wend
End If
rstXyzErrors.Close: Set rstXyzErrors = Nothing
Set db = Nothing

End Sub

Private Sub RemoveVBComponentIfExists( _
vbcs As VBIDE.VBComponents, _
strModuleName As String _
)
Dim vbcModule As VBIDE.VBComponent
On Error Resume Next
Set vbcModule = vbcs(strModuleName)
On Error GoTo 0
If Not (vbcModule Is Nothing) Then
vbcs.Remove vbcModule
Set vbcModule = Nothing
End If
End Sub

Private Function CreateNewVBModule( _
vbcs As VBIDE.VBComponents, _
strModuleName As String _
) As VBIDE.VBComponent
Dim vbcResultModule As VBIDE.VBComponent
Set vbcResultModule = vbcs.Add(vbext_ct_StdModule)
vbcResultModule.Name = strModuleName
Set CreateNewVBModule = vbcResultModule
End Function
</basXyzCodeGeneration>
Running GenerateXyzErrDefs generates the basXyzErrorDefinitions module as
follows...

<basXyzErrorDefinitions>
Option Compare Database
Option Explicit

Public Function XyzErrDontDoThat() As clsErrorDefinition
Static sobjErrDefinition As clsErrorDefinition
If sobjErrDefinition Is Nothing Then
Set sobjErrDefinition = New clsErrorDefinition
sobjErrDefinition.Setup _
1001, _
"Hey! Don't do that!"
End If
Set XyzErrDontDoThat = sobjErrDefinition
End Function

Public Function XyzErrNotThatEither() As clsErrorDefinition
Static sobjErrDefinition As clsErrorDefinition
If sobjErrDefinition Is Nothing Then
Set sobjErrDefinition = New clsErrorDefinition
sobjErrDefinition.Setup _
1002, _
"Woah! Don't do that either!"
End If
Set XyzErrNotThatEither = sobjErrDefinition
End Function

Public Function XyzErrAttemptedInstanceReinit() As clsErrorDefinition
Static sobjErrDefinition As clsErrorDefinition
If sobjErrDefinition Is Nothing Then
Set sobjErrDefinition = New clsErrorDefinition
sobjErrDefinition.Setup _
1003, _
"Attempted to reinitialize an instance of an object type that does
not allow multiple initializations per instance."
End If
Set XyzErrAttemptedInstanceReinit = sobjErrDefinition
End Function
</basXyzErrorDefinitions>
Nov 12 '05 #1
7 2689
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:06********************************@4ax.com...
Here is some code to generate code for raising and getting information about custom errors in an application. Executing the GenerateXyzErrDefs procedure generates the code.


I am completely baffled by this.

Why generate a basXyzErrorDefinitions module that contains nothing but
duplicate functions?

Why not generate a class that not only raises and reports on the error, but
also initializes the pairs?
Nov 12 '05 #2
On Mon, 03 Nov 2003 12:33:47 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:06********************************@4ax.com.. .
Here is some code to generate code for raising and getting information

about
custom errors in an application. Executing the GenerateXyzErrDefs

procedure
generates the code.


I am completely baffled by this.

Why generate a basXyzErrorDefinitions module that contains nothing but
duplicate functions?

Why not generate a class that not only raises and reports on the error, but
also initializes the pairs?


I'm not sure I understand the question, so I'n not sure if this addresses it,
but...

Instances of clsErrorDefinition represent individual error types. Each of the
functions in basXyzErrorDefinitions accesses an instance of clsErrorDefinition
for a particular type.

I don't want to generate separate class modules for each case because
A. That many class modules would be a big clutter in the VBE.
B. Calling code would have the extra code and extra overhead of creating an
instance of whichever class before using it.
C. It is nice for the calling code to be able to implement functions that
accept or return a value of type clsErrorDefinition, and use early binding
rather than having to use Object type because multiple class types are
possible, and resolve everything else at run-time. An Interface could solve
that, but wouldn't be compatible with Access 97 - which is nice to be.

If I don't generate separate class -modules- for each case, then something has
to initialize them and provide access to the correct one by name. I could
have passed just the ID, and let the class look up the rest from the table,
but the generator is already reading the table, and the resulting code is nto
to be directly maintained anyway, so why not just dump all the info into the
code during code generation?

We're not worried about duplication in the generated code because it's not
manually maintained. The function pattern need only be maintained in one
place in the code generator, and the error details need be maintained in only
one place, the table. I guess it's kind of like doing a mail merge in MS
Word. I probably should have a comment automatically inserted at the top of
the basXyzErrorDefinitions module saying how to maintain and regenerate it, so
it's obvious to anyone maintaining the code.

Note - in my original code, the following line should be removed because it
was part of an experiment that failed, and nothing now uses it...
Private Const mycVBErrMethodNotApplicableInContxt = 444&

Nov 12 '05 #3
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:6v********************************@4ax.com...
On Mon, 03 Nov 2003 12:33:47 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb> wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:06********************************@4ax.com.. .
Here is some code to generate code for raising and getting informationabout
custom errors in an application. Executing the GenerateXyzErrDefs

procedure
generates the code.


I am completely baffled by this.

Why generate a basXyzErrorDefinitions module that contains nothing but
duplicate functions?

Why not generate a class that not only raises and reports on the error, butalso initializes the pairs?


I'm not sure I understand the question, so I'n not sure if this addresses

it, but...
We've been through this before and I was completely rejected, but here goes.

Now that you have decided that using a class is going to be part of the
process, why not make it THE process.
Instances of clsErrorDefinition represent individual error types. Each of the functions in basXyzErrorDefinitions accesses an instance of clsErrorDefinition for a particular type.
You're using the class as just another function in the process instead of
encapsualting the process in the class.
I don't want to generate separate class modules for each case because
A. That many class modules would be a big clutter in the VBE.
There would only be one class.
B. Calling code would have the extra code and extra overhead of creating an instance of whichever class before using it.
Your calling code has to go through the process of calling a function which
has to go through the process of creating an instance of the class. Where's
the extra overhead if the calling code simply creates an instance instead?
C. It is nice for the calling code to be able to implement functions that
accept or return a value of type clsErrorDefinition, and use early binding
rather than having to use Object type because multiple class types are
possible, and resolve everything else at run-time. An Interface could solve that, but wouldn't be compatible with Access 97 - which is nice to be.
Once again, there only needs to be one class. One class that contains all
the error numbers and descriptions. One class that exposes the error
numbers as property get routines. One class that raises the correct error
through a public method that takes one of the error numbers defined
by itself as a parameter.
If I don't generate separate class -modules- for each case, then something has to initialize them and provide access to the correct one by name. I could
have passed just the ID, and let the class look up the rest from the table, but the generator is already reading the table, and the resulting code is nto to be directly maintained anyway, so why not just dump all the info into the code during code generation?
Dump all the info into the class during code generation.
We're not worried about duplication in the generated code because it's not
manually maintained.


It's still duplicate code and it's still ugly and completely un-necessary.
In my view, of course.

The code generation stuff you posted looks interesting and I will be taking
a further look at it.



Nov 12 '05 #4
rk*@yabba.dabba.do.rochester.rr.bomb (rkc) wrote in
<3d*******************@twister.nyroc.rr.com>:
Once again, there only needs to be one class. One class that
contains all the error numbers and descriptions. One class that
exposes the error numbers as property get routines. One class that
raises the correct error through a public method that takes one of
the error numbers defined by itself as a parameter.


Steve's gone in a very different direction than what I foresaw.

He's using a table to store his error definitions, as I suggested,
and his reason is to make it possible to keep multiple attributes
of a single error correlated.

I had suggested that once you do this, you really need only two
things:

1. a module with the constants for your error numbers (generated in
code).

2. a module or class with the functions necessary to raise the
error.

You'd pass the class the error constant and the class would then
raise the error with the appropriate error description and do
whatever else you wanted it to do. The class itself could have as
many methods and properties as you wanted, but I would make them
all generic, rather than generating a class with properties
specific to all your errors.

Steve's objection to the table was that you couldn't enforce it
with compiling. His solution to that was to autogenerate the
constants. My thought is that all you really need are the constants
for the error numbers themselves (which are actually the PK of your
table) as your way of getting to all the other attributes of your
errror. And your class or module for raising your error and
examining its attributes would simply be a lookup of a particular
error code in the error table.

With this solution you get:

1. simple, generic code.

2. as many custom attributes of your errors as you need.

3. with the auto-generated module of error number constants, you
get compile-time enforcement of error codes without needing to
worry about correlating a set of multiple error attributes for each
error, since the error number is itself a pathway into the lookup
for all the other attributes.

You'd only need one instance of your error class (if you went that
route), since you can only raise one error at a time.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #5
On Mon, 03 Nov 2003 20:26:03 GMT, dX********@bway.net.invalid (David W.
Fenton) wrote:
rk*@yabba.dabba.do.rochester.rr.bomb (rkc) wrote in
<3d*******************@twister.nyroc.rr.com>:
Once again, there only needs to be one class. One class that
contains all the error numbers and descriptions. One class that
exposes the error numbers as property get routines. One class that
raises the correct error through a public method that takes one of
the error numbers defined by itself as a parameter.


Steve's gone in a very different direction than what I foresaw.

He's using a table to store his error definitions, as I suggested,
and his reason is to make it possible to keep multiple attributes
of a single error correlated.

I had suggested that once you do this, you really need only two
things:

1. a module with the constants for your error numbers (generated in
code).

2. a module or class with the functions necessary to raise the
error.

You'd pass the class the error constant and the class would then
raise the error with the appropriate error description and do
whatever else you wanted it to do. The class itself could have as
many methods and properties as you wanted, but I would make them
all generic, rather than generating a class with properties
specific to all your errors.

Steve's objection to the table was that you couldn't enforce it
with compiling. His solution to that was to autogenerate the
constants. My thought is that all you really need are the constants
for the error numbers themselves (which are actually the PK of your
table) as your way of getting to all the other attributes of your
errror. And your class or module for raising your error and
examining its attributes would simply be a lookup of a particular
error code in the error table.

With this solution you get:

1. simple, generic code.

2. as many custom attributes of your errors as you need.

3. with the auto-generated module of error number constants, you
get compile-time enforcement of error codes without needing to
worry about correlating a set of multiple error attributes for each
error, since the error number is itself a pathway into the lookup
for all the other attributes.

You'd only need one instance of your error class (if you went that
route), since you can only raise one error at a time.


My thinking was that if I'm generating the code anyway, why not take this a
step farther than simply generating a list of constants and a way to look up
the other information about the constants. Why not generate named functions
that directly return class instances that encapsulate all the properties and
methods of the errors.

To raise a "DontDoThat" error, just say XyzErrDontDoThat().Raise. You don't
have to think in terms of looking things up at all, just tell the error to
raise itself. Would you agree or disagree this is an improvement over
generating constants and passing them to one or more lookup functions.
Nov 12 '05 #6
no****@nospam.nospam (Steve Jorgensen) wrote in
<j9********************************@4ax.com>:
On Mon, 03 Nov 2003 20:26:03 GMT, dX********@bway.net.invalid
(David W. Fenton) wrote:
rk*@yabba.dabba.do.rochester.rr.bomb (rkc) wrote in
<3d*******************@twister.nyroc.rr.com>:
Once again, there only needs to be one class. One class that
contains all the error numbers and descriptions. One class that
exposes the error numbers as property get routines. One class
that raises the correct error through a public method that takes
one of the error numbers defined by itself as a parameter.
Steve's gone in a very different direction than what I foresaw.

He's using a table to store his error definitions, as I
suggested, and his reason is to make it possible to keep multiple
attributes of a single error correlated.

I had suggested that once you do this, you really need only two
things:

1. a module with the constants for your error numbers (generated
in code).

2. a module or class with the functions necessary to raise the
error.

You'd pass the class the error constant and the class would then
raise the error with the appropriate error description and do
whatever else you wanted it to do. The class itself could have as
many methods and properties as you wanted, but I would make them
all generic, rather than generating a class with properties
specific to all your errors.

Steve's objection to the table was that you couldn't enforce it
with compiling. His solution to that was to autogenerate the
constants. My thought is that all you really need are the
constants for the error numbers themselves (which are actually
the PK of your table) as your way of getting to all the other
attributes of your errror. And your class or module for raising
your error and examining its attributes would simply be a lookup
of a particular error code in the error table.

With this solution you get:

1. simple, generic code.

2. as many custom attributes of your errors as you need.

3. with the auto-generated module of error number constants, you
get compile-time enforcement of error codes without needing to
worry about correlating a set of multiple error attributes for
each error, since the error number is itself a pathway into the
lookup for all the other attributes.

You'd only need one instance of your error class (if you went
that route), since you can only raise one error at a time.


My thinking was that if I'm generating the code anyway, why not
take this a step farther than simply generating a list of
constants and a way to look up the other information about the
constants. Why not generate named functions that directly return
class instances that encapsulate all the properties and methods of
the errors.


As long as a human being is going to be progamming in the database,
seems to me you want the amount of generated code to be as small
as possible.
To raise a "DontDoThat" error, just say XyzErrDontDoThat().Raise.
You don't have to think in terms of looking things up at all, just
tell the error to raise itself. Would you agree or disagree this
is an improvement over generating constants and passing them to
one or more lookup functions.


No, because it proliferates a huge amount of duplicative code.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #7
On Tue, 04 Nov 2003 16:50:30 GMT, dX********@bway.net.invalid (David W.
Fenton) wrote:

....
My thinking was that if I'm generating the code anyway, why not
take this a step farther than simply generating a list of
constants and a way to look up the other information about the
constants. Why not generate named functions that directly return
class instances that encapsulate all the properties and methods of
the errors.
As long as a human being is going to be progamming in the database,
seems to me you want the amount of generated code to be as small
as possible.


I don't know if that should be a concern. Generated code should be treated as
a black box. Only the metacode and code generator need be dealt with by the
programmer.
To raise a "DontDoThat" error, just say XyzErrDontDoThat().Raise.
You don't have to think in terms of looking things up at all, just
tell the error to raise itself. Would you agree or disagree this
is an improvement over generating constants and passing them to
one or more lookup functions.


No, because it proliferates a huge amount of duplicative code.


I disagree on this. I do have a problem with my own code, though. Having
part of the code split between the error definition class and the code
generator is not good. Next time I have time, I'll take another stab. I may
decide to do it the way you were suggesting - we'll see what I come up with.
Nov 12 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Ziggi | last post by:
Hi ! I have an ISAPI instalation of PHP over IIS5 server on Windows 2000. Everything works fine but as I am under website development I would like to keep PHP error messages turned on - for my...
0
by: Doug | last post by:
Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Lines: 14 Message-ID: <9DxFc.23833$bs4.23734@newsread3.news.atl.earthlink.net> Date: Sat, 03 Jul 2004...
8
by: Grant Richard | last post by:
Using the TcpListener and TcpClient I created a program that just sends and receives a short string - over and over again. The program is fine until it gets to around 1500 to 1800 messages. At...
1
by: Mike Hunter | last post by:
(Please CC me on any replies as I'm not on the list) Hi, After a recent power failure, a program that uses a pgsql backend (netdisco) started to send me nastygrams. I tried the author's...
2
by: Florian G. Pflug | last post by:
Hi Since sometime yesterday, my postgresql (7.4.5) reports "ERROR: cannot compare arrays of different element types", when I analyze a specific table in my database. Here is the tables...
1
by: Jarod | last post by:
Hey When I put my control into DetailsView in a template I see it and it seems as working ok. After compile it works on the page. But in normal view in designer I don't see my detailsView instead...
2
by: Mike Hofer | last post by:
In my ASP.NET application, *one* page would not render in the application. All others would show up just fine, but when the user clicked the button to browse to this one page, I'd get a nasty error...
5
by: Alias | last post by:
Hi - I'm trying to implement a custom RoleProvider based on the SqlRoleProvider. I keep receiving a an error that it can't load type 'MyRoleTest.MyRoleProvider' when trying to load my...
13
by: Kevin Liebowicz | last post by:
Yes, I wasted the past two days trying to fix this. Yes, this is on a Win2003 Server. Yes, this machine is a domain controller. Yes, I seen the dozens of KB articles like this one:...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.