• (cs)

    Woaw.

    I guess he's getting paid per line as well. And well, using lots of upper-case constants makes your code look like C++, which means you must be a good developer, right?

    Nah, actually I happen wonder from time to time about 'appropriate' use of constants, as well. But I'd never use them for stored procedure parameters :).

    WTF.

    Frederik.

  • (unregistered)

    I've got a problem with this part:
    'Stored Procedure Parameter Indices
         Const SP_PARAM_INDEX_IN_MESSAGE_ID As Integer = 0
         Const SP_PARAM_INDEX_IN_USER_ID As Integer = 1
         Const SP_PARAM_INDEX_IN_DOC_TYPE As Integer = 2

    Everybody knows that it's not good to hard code magic numbers like that. What will he do when the definition of 0, 1 or 2 changes?

  • (cs)

    OMG! He used CType()!

    This almost looks like it's written by somebody who knows what casting is!

    He CANT be a pure VB 'programmer'. That would be an even bigger WTF.

  • (cs) in reply to DJDanny
    DJDanny:
    OMG! He used CType()!

    This almost looks like it's written by somebody who knows what casting is!

    He CANT be a pure VB 'programmer'. That would be an even bigger WTF.


    However, looks like he doesn't realise that .NET lets VB 'programmers' into the world of assigning to variables at the point of declaration, so he's let himself down a bit there.
  • (cs)

    Anyone else think there's a line somewhere else in the file that says:

    Const msUP_DUPLICATE_COUNT as String = "msUP_DUPLICATE_COUNT"

    ?

     I also like the assignment of the 'dataConnection' parameter to the 'connectionString' local for no apparent reason.

    And it's just brilliant to pass the connectionString into the function, but rely on members (hopefully not globals) to get the appID, userID, docType, and the DAB helper.  I'm sure that value is much more dynamic than the procedure parameters.

  • (unregistered)

    <font style="BACKGROUND-COLOR: #efefef">OMG... He made constants out of ENUM? How crazy that is...</font>

  • (cs)

    I wasn't aware that single-statement Dim-and-Set was compulsory now. Thanks, DJDanny, for cluing us all in. (It's a style choice, that's all, and this guy has already proven that he doesn't mind typing the odd extra character.)

    This is rather like applying a major project management framework to a macro, innit? Kinda beautiful in its overdoneness. It's like a fractal -- no matter how closely you look, the same level of detail in adherence to best practices.

  • (unregistered)

    A the good ol, SCREAMING_WHILE_BREAKING_YOUR_FINGER_TYPING_THAT_DAMN_UNDERSCORE
    style.

    Good times right there.

  • (cs)

    other than being a little verbose, and being a little "constant-crazy", there's really nothing wrong with this code at all.  

  • (unregistered)

    Yeah, he used CType(), but should be using DirectCast(), so that's not overly impressive.

  • (cs) in reply to
    Anonymous:

    <font style="BACKGROUND-COLOR: #efefef">OMG... He made constants out of ENUM? How crazy that is...</font>


    Yes, that way it's going to be an easy fix when the value of SqlDbType.NVarChar changes...  this is inspiring... Take a look at this little gem:

    <font size="2">

    </font><font color="#0000ff" size="2">class</font><font size="2"> DownWithMagicNumbers {
    </font><font color="#0000ff" size="2">  public</font><font size="2"> </font><font color="#0000ff" size="2">const</font><font size="2"> </font><font color="#0000ff" size="2">int</font><font size="2"> Zero = 0;
    </font><font color="#0000ff" size="2">  public</font><font size="2"> </font><font color="#0000ff" size="2">const</font><font size="2"> </font><font color="#0000ff" size="2">int</font><font size="2"> One = 1;
    }

    </font><font color="#0000ff" size="2">enum</font><font size="2"> ImAllAboutBestPractices {
      Zero = DownWithMagicNumbers.Zero,
      One = DownWithMagicNumbers.One
    }

    </font>
  • (cs) in reply to Guayo

    sadly this doesn't compile:

    <font size="2">

    </font><font color="#0000ff" size="2">class</font><font size="2"> DownWithMagicNumbers {
      </font><font color="#0000ff" size="2">public</font><font size="2"> </font><font color="#0000ff" size="2">const</font><font size="2"> </font><font color="#0000ff" size="2">int</font><font size="2"> Zero = ImAllAboutBestPractices.Zero;
      </font><font color="#0000ff" size="2">public</font><font size="2"> </font><font color="#0000ff" size="2">const</font><font size="2"> </font><font color="#0000ff" size="2">int</font><font size="2"> One = ImAllAboutBestPractices.One;
    }

    </font><font color="#0000ff" size="2">enum</font><font size="2"> ImAllAboutBestPractices{
      Zero = DownWithMagicNumbers.Zero,
      One = DownWithMagicNumbers.One
    }

    [:^)]

    </font>

  • (unregistered) in reply to

    for those wondering Paul Vick has said that you really should be using the C functions, not DirectCast: http://www.panopticoncentral.net/archive/2003/07/10/149.aspx

  • (unregistered)

    Why does he bother to use variables for all the indexes when he bases how big the array is going to be off of the value of what is currently the last index (SP_PARAM_INDEX_IN_DOC_TYPE).  What if @docType is moved to be the first parameter, or a new parameter is put after it?  One more thing to change that he might not catch.  He should create YET_ANOTHER_LOVELY_VARIABLE and store set it to how many parameters there are.

  • (cs) in reply to
    :
    for those wondering Paul Vick has said that you really should be using the C functions, not DirectCast: http://www.panopticoncentral.net/archive/2003/07/10/149.aspx


    Very interesting, thanks for the link.

    What is the difference between CType(<object>, Integer) and CInt(<object>)? They are both compiled inline so it isn't speed, I'm sure that someone can fill me in?[8-|]
  • (cs) in reply to skicow
    skicow:


    What is the difference between CType(<object>, Integer) and CInt(<object>)? They are both compiled inline so it isn't speed, I'm sure that someone can fill me in?


    Isn't CInt() just a legacy function to help VB 'programmers' adjust to the rigours of OO programming?
  • (cs) in reply to DJDanny

    Ctype is also "old VB" (it's been around as long as user-defined types have been); the .NET version is .ToType() (if the current type implements IConvertible). OO is not particularly rigorous (there are procedural languages that would make you cry), nor is it particularly difficult to grok.

  • (cs)

    I don't think this is bad at all.  It may be a little overdone but I'd much rather this than the magic number/no comments jungle you too often find lurking for you.

    My only kvetch would be:

         Const SP_PARAM_TYPE_IN_MESSAGE_ID As SqlDbType = SqlDbType.NVarChar
         Const SP_PARAM_TYPE_IN_USER_ID As SqlDbType = SqlDbType.Int
         Const SP_PARAM_TYPE_IN_DOC_TYPE As SqlDbType = SqlDbType.VarChar

    I'd be willing to just use the SqlDbType directly but overall I'd be happy to get this code.

  • (cs) in reply to DJDanny
    DJDanny:
    Isn't CInt() just a legacy function to help VB 'programmers' adjust to the rigours of OO programming?


    Not at all. I prefer VB for it's increase in productivity. CInt is a perfect example.

    CInt("5") compiles to Int.Parse("5")
    CInt(5.5) compiles to (int)5.5
    etc ...

    I don't think it's a bad practice, and I don't think it has anything to do with OO vs Non-OO -- I know what it does, how it works, and it's a nice shortcut.

    I can say the same about a lot of functions I use reguarly, such as Right() and IsNumeric. They're all a wrapper to the "real" way to do, so why not use them? I think Right(str,2) is a bit easier to read than str.substring(str.length-2,2).
  • (cs) in reply to DJDanny
    DJDanny:
    [image] skicow wrote:


    What is the difference between CType(<object>, Integer) and CInt(<object>)? They are both compiled inline so it isn't speed, I'm sure that someone can fill me in?


    Isn't CInt() just a legacy function to help VB 'programmers' adjust to the rigours of OO programming?

    Not so much. Cint() is just syntactic shorthand for CType(x, Integer). I just checked, they both compile to this (if used on a string):
     IL_0008:  call       int32 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.IntegerType::FromString(string)

    Now there is a difference between CType and DirectCast. CType will do fancy stuff like you see above (converting a string to an integer). DirectCast only works if the object *actually* is of the type you're casting too, e.g.:
    Dim a As Object = "5"

    Dim b As String = CType(x, String) ' This works.
    Dim c As String = DirectCast(x, String) ' This also works, and is faster too.
    Dim d As Integer = CType(x, Integer) ' This works.
    Dim e As Integer = DirectCast(x, Integer) ' This'll fail at runtime (InvalidCastException)

    (Note: I don't actually name my variables a, b, c etc. when writing real code, don't worry. [:)] On that note, anybody here remember DEFINT A-Z?)
  • (unregistered) in reply to
    :
    for those wondering Paul Vick has said that you really should be using the C functions, not DirectCast: http://www.panopticoncentral.net/archive/2003/07/10/149.aspx


    Wrong.

    In fact, the article says TO use it when you know the cast will succeed, because it improves performance.

    Try checking with Microsoft.

    "the run-time performance of DirectCast is better than that of CType"
  • (cs)

    Cool, I thought that CInt was the 'shorthand' for Ctype(<object>, Integer) but I wasn't sure and I knew you guys/girls would know [:)]

  • (unregistered)

    Of course I know it improves performance, but you are sacraficing flexibility to do so.  It is very, very rarely needed to have that small amount of performance gained, and giving up flexibility for that is just silly.

    I keep running across DirectCast from people proving how hard core of a VB developer they are.  [^o)] If you want to impress your friends and neighbors by using DirectCast and causing more work for yourself, how about you just go the full nine and use assembly.  Because coding in assembly certainly would be faster than VB.net and DirectCast.

  • (unregistered) in reply to

    How exactly is it more work?

    If I stuff an ArrayList full of Integers, do you think I'm going to get an Invalid Cast Exception when I try to get them out?  Not a chance.  So why would you not use DirectCast() in this situation?

    If I put a bunch of myClass's into a Hashtable, should I CType() them back out or DirectCast them?

    Of course I would DirectCast() them out, because it is going to work and it is going to be faster.  Using CType() in this situation means you do not know what you are doing and are scared it might "break" if you use DirectCast(), which of course it wouldn't.

  • (unregistered) in reply to
    :
    Of course I know it improves performance, but you are sacraficing flexibility to do so.  It is very, very rarely needed to have that small amount of performance gained, and giving up flexibility for that is just silly.

    I keep running across DirectCast from people proving how hard core of a VB developer they are.  [^o)] If you want to impress your friends and neighbors by using DirectCast and causing more work for yourself, how about you just go the full nine and use assembly.  Because coding in assembly certainly would be faster than VB.net and DirectCast.
  • (cs) in reply to
    :
    A the good ol, SCREAMING_WHILE_BREAKING_YOUR_FINGER_TYPING_THAT_DAMN_UNDERSCORE
    style.

    Good times right there.


    If you ask me, it's more legible than SCREAMINGWHILEBREAKINGYOUREYESWITHOUTTHATDAMNUNDERSCORE
  • (unregistered)

    My point is that ExecuteScalar is going to return an object.  We are using DirectCast on it, in this case converting it to an integer.

    Does ExecuteScalar return an object that deep down really is an integer? I know the answer, but that's because I'm a huge nerd.  I mean ExecuteScalar could return strings, dates, integers, doubles, who knows!  Maybe even null, er nothing, if in this case this is an invalid message id or user id.

    So, as a developer, you've got two choices.  Dig deep into the documentation / reflector to figure out if DirectCast will in fact always work because this method will ALWAYS return an integer, or use CInt and loose a picosecond of performance time. 

    Like I said, the vast majority of the time, you simply don't need that level of optimization.  Sure it's great for the situations you detailed (just like Paul Vick pointed out), but in this case it isn't appropriate.

  • (cs) in reply to Alex Papadimoulis
    Alex Papadimoulis:


    I think Right(str,2) is a bit easier to read than str.substring(str.length-2,2).


    At least you can be sure substring() is zero-based. With Right(), you're just never quite sure!
    (another gripe with VB - some things are zero-based, some aren't. In languages designed for people who know what they're doing, you know everything is zero-based!)
  • (cs) in reply to DJDanny

    No, you don't. You merely know that native types/classes are going to be zero-based, and then only if that is the convention in that particular language. You have no idea at all what you'll find when you connect to anything that either (a) didn't come in the box; or (b) you didn't create yourself. Making assumptions is not a good sign....

    (Do you know why C-derived languages use zero-based arrays? Hint: it's got nothing to do with making things easier for programmers.)

  • (cs) in reply to
    :
    My point is that ExecuteScalar is going to return an object.  We are using DirectCast on it, in this case converting it to an integer.

    Does ExecuteScalar return an object that deep down really is an integer? I know the answer, but that's because I'm a huge nerd.  I mean ExecuteScalar could return strings, dates, integers, doubles, who knows!  Maybe even null, er nothing, if in this case this is an invalid message id or user id.

    I don't think anybody here is contesting you should always use DirectCast. But there's no sense in saying you should never use it either. Both CType and DirectCast have their uses. A good VB developer knows when it's appropriate to use either of them, and if you're not sure (for example in the case of some library fuction returning an Object and you're not awfully familiar with it), use CType.

    There are also cases where using CType is explicitly bad. You might get an Object from something that should be an Integer. Maybe someday some exceptional condition causes it to be a String. Then you have to ask yourself what should happen: should the string be parsed or the conversion fail? In the latter case, you must use DirectCast.
  • (cs)

    Y' know, when you stop and think about it, VB's "Dim" keyword is very silly in more ways than one.

  • (cs) in reply to doidydoidy

    Would you rather type "Dimension"?

  • (unregistered)

    alright, I did some performance testing on my trusty laptop.  Keep in mind it's an 833mhz Pentium, so your mileage will vary.

    My findings were quite drammatic!  DirectCast was TEN TIMES faster than CType.  In a simple test of using CType vs DirectCast one billion times (to get a good average time), I found that a conversion of an integer took 0.00000000061seconds, where as DirectCast could do it in a svelt 0.000000000061s.  If you did a million casts you'd notice a time savings of FIVE ENTIRE MILLISECONDS.  Maybe even less if your computer doesn't suck.

    Smart ass comments aside, it's obvious that DirectCast isn't going to do much besides make you feal like you are optimizing your code, when all you are doing are making very small changes in performance that make your code a little less maintainable.

    As for the example from Unforgiven where you have a function that returns and object that's usually an integer, but rarely a string you'd want to use DirectCast, well, there are much better ways of handling this.  Obviously if we are talking performance, we know that exceptions ain't cheap.  You'd be much better off using the the TypeOf operator to figure out the return value and handle it appropriately (and this might involve throwing your own exception).

    I don't know, maybe I'm an idiot.  But Paul Vick stated the reason DirectCast exists, and why it should use the ctype functions.  I associate the DirectCast opperator with something like Erl from VB6.  Sure you could use it.  But there's a GOOD reason you don't see too many code samples out of Microsoft using it.  There's a good reason books don't use it.  And it is not because the authors aren't aware of it.  It's just overkill, and I feal can cause you some pretty big headaches if you use it without being fully aware of all the implications (and even when you use it, you aren't really gaining that much performance).

    The risk / reward of DirectCast just isn't there.

  • (unregistered)

    What is DAB?
    Is it the DAAB SqlHelper?

    If it isn't and it does less than the DAAB, thats a WTF.

    If it is, then this code is much more of WTF that just some really stupid constants.

    The DAAB SqlHelper would allow the function body to be reduced to a call and a cast.

    dbQueryReturn = SqlHelper.ExecuteScalar( _           
    connectionString _           
    , CommandType.StoredProcedure _           
    , storedProcedureName            
    , appId, userId , docType
     
              )

  • (unregistered) in reply to Stan Rogers
    Stan Rogers:

    (Do you know why C-derived languages use zero-based arrays? Hint: it's got nothing to do with making things easier for programmers.)


    OK so we know that in .NET EVERYTHING is 0-based, but please, do tell!
  • (cs)

    Oh come on! The one time some good code shows up and it's slagged off for being "too good"! Yes it's a bit over the top, but it's hardly a WTF!

  • (unregistered) in reply to

    >> OK so we know that in .NET EVERYTHING is 0-based, but please, do tell!

    because pointer[x] in c is syntatic sugar for (pointer +  (sizeof(type)   x) where
    pointer is a (type
    )

  • (cs) in reply to

    No, it's equivalent to *(pointer + x). Pointer arithmetic always takes the size of the pointer target type into account. Note that this equivalence means you can also write x[pointer], which is a useful trick for writing obfuscated C.

  • (cs) in reply to Ben Hutchings

    Zackly. My point was, though, that it's largely a historical relic, particularly as it applies to a language like Java. It isn't "right and proper", it's "easier to compile", and from a high-level programmability point of view (as opposed to the bit-twiddler's point of view), it simply makes the language less accessible. Any six-year-old can tell you that if you have ten numbered things and you want the sixth one, you should ask for number 6. Only someone who's been at this game too long would ask for number 5. Given that compilers can figure things like index-to-address mapping all by their lonesomes these days, I would consider using zero indexing in any new high-level language a fundamental flaw -- it's a convention now, and that's about the extent of it. (Pointer math can also be compiler-resolved, so even that isn't a valid argument anymore.)

  • (unregistered) in reply to

    <font style="BACKGROUND-COLOR: #efefef">Also, DirectCast would prevent you from writing a helper function that "unpacked" those aforementioned arrays for you, no matter what they contained.  Of course, if you're fond of that kind of dynamism, you're probably writing your code in Lisp, not VB.</font>

  • (cs) in reply to Stan Rogers

    Oh, and you DON'T know that everything in .NET is zero-based; not any more than you'd know it in Java. You have no assurance that an API that I expose to you doesn't use the Fibonacci sequence starting at some arbitrary value as index values for items in a "collection", or that I personally don't like to see the number eleven used as an index value. What you know are native types, and types derived from native types. You can also be reasonably sure about the stuff you write, but it's almost always safer to assume that the guy who wrote the module you're trying to integrate with is psychotic, or at least a little bit deranged. RTFM (or RTFD, the D standing for documentation), assume nothing, and code for disaster.

  • (cs)

    Again,I have to agree with Stan.

    What is great about C/C++ is that they are about as close as you can get to assembly language without actually using it, and thus they expose many things that you have to deal with when writing assembly  -- such as dealing with an array of memory locations and storing/retrieving data from them.  If your array starts at location foo, then the first item is located at foo, which is foo+0, not foo+1.  Thus, zero-based indexes were born.  And C/C++, dealing directly with pointers to memory locations and implementing arrays as low-level as they do, therefore works the same way.

    But to imply that "all real programming languages" or "all real programmers" MUST always use 0-based arrays is simply ridiculous.

  • (unregistered)

    Stan says " I would consider using zero indexing in any new high-level language a fundamental flaw".

    Well, that's your privilege, but you'll find a whole bunch of language designers will disagree with you. It's a choice, with arguments for either option.

    I would also say that your six year old is not a good argument - for example, for the first year of its life, it was zero years old. The first minute of the hour will show as 00 on a digital display. There are plenty of other examples of offsets in real life as well as in computer languages, but your average 6 yo just won't get it.

    Anonymouse

  • (cs) in reply to

    You have cardinals and ordinals mixed -- they aren't the same. And language designers are as prejudiced by their experience (and desire to keep the craft arcane) as anyone else.

  • (cs)

    At less than 1 year old, the child's AGE is 0 .... but which year of his life is he/she currently in?  Year 1. The FIRST year of his life, not the zero-th year.

    Same thing with the clock -- the minutes themselves are labelled from 0-59, but the minute NUMBER is from 1-60.

  • (cs)

    This has the mark of a new programmer trying to be a good citizen. Or, possibly an experianced programmer who, after years of writing very sloppy code, finally got religion and is making a concerted effort to DO_THING_THE_RIGHT_WAY.

    In either case, when the pendulum swings back a bit, we will see a happy medium. At least this is someone trying to do a good job.

  • (unregistered)

    Jeff: At less than 1 year old, the child's AGE is 0 .... but which year of his life is he/she currently in? Year 1. The FIRST year of his life, not the zero-th year.

    Which is pretty much what I said: "for the first year of its life, it was zero years old".

    Stan: And language designers are as prejudiced by their experience (and desire to keep the craft arcane) as anyone else.

    None of the language designers I've met have expressed any desire to make their languages arcane. (Why bother, when there's APL, Lisp, etc. already out there?) Mostly, they want to produce a tool to allow communication between human and computer. There are all sorts of issues at both ends of this - working with 1-based indexing may make compilers more complex, thus making communication at the computer end more difficult while making communication with an average human easier. Contrarily, 0-based indexing, though non-obvious to a naive programmer, may be easier for the computer.

    Now, your attitude seems to be that the higher-level language shouldn't make allowances for the computer end - after all, compiler writing is something with quite a history behind it. That's an understandable point of view. But lacking as we are a universal computer language good for everyone and everything, different languages are designed for different purposes. Sometimes, that means that the choices that would apparently make a language easier actually make certain problems harder to express.

    Of course, if your definition of a high-level language includes that array indexing starts at 1, then I can't argue. Your expectation that the numbers are ordinals rather than offsets isn't mine, though. (Obviously, I'm prejudiced.) Meanwhile, I expect languages to continue appearing with 0 and with 1-based array indexing.

  • (unregistered) in reply to

    Oh wonderful - the preview mode doesn't match what actually appears.

  • (cs) in reply to

    No it doesn't, so we'll let the HTML slide -- but I'll call you flat wrong on the ordinals-versus-offsets call. I am not DEFINING high-level languages by 1-indexing. I am defining high-level languages as programming tools sufficiently abstracted from the hardware the end-product will run on as to obviate consideration of the hardware (at least prior to optimization). An array is an abstract collection of data in a high-level language, not a memory address with offsets -- even with pointers, you are looking at abstractions (unless you have hard-coded your execution space), and the compiler/interpreter can handle to memory location mapping. There is no good reason to force or even expect zero-indexing anymore, except as convention.

  • (cs)

    DirectCast might be good for XML/database processing with a schema - if your field says it has to be an integer (or string or whatever) and it isn't, fail. Let your error routines pick up the slack. That's what most XML processors do anyway. (Xalan's core dump/stack trace is my favorite.)

    I'm not sure how flexible the method typing is, though, having never used it.

Leave a comment on “Some Good VB, for a change”

Log In or post as a guest

Replying to comment #:

« Return to Article