-4

Is there a best practice for opening an excel workbook? I have this function

Function openWorkbook(workbookpath As String, Optional worksheetname As String)
  If IsMissing(worksheetname) Then worksheetname = "Sheet1"
  'Test workbookpath
  Dim wb As Workbook
  Dim ws As Worksheet
  Dim fso As Scripting.FileSystemObject
  Dim wbname As String
  wbname = fso.GetFileName(workbookpath)
  Dim thisIsSoStupid As Boolean
  thisIsSoStupid = True

  'test if workbook is open
  For Each wb In Workbooks
    If wb.Name = wbname Then
        Set openWorkbook = wb
        thisIsSoStupid = False
        break
    End If
  Next

  If thisIsSoStupid And Dir(workbookpath) <> 0 Then
   openWorkbook = Workbooks.Open(workbookpath)

  Else
    openWorkbook = False
  End If
End Function

I'd like to do something like g = openWorkBook(path)||false which is a javascript shortcut or $g = fopen($path, 'w') or die('bugger'); but of course, if it can't find the file, it will return false and I can't evaluate a false if my code is expecting an object. Do I have to on error resume and then catch the error? I hate the stupid error crap. It's an invitation to spaghetti code

ThunderFrame
  • 9,352
  • 2
  • 29
  • 60
  • Your question seems to be mainly a complaint that VBA doesn't have the same syntax as other languages you're more familiar with ;-) What is "best practice" in VBA depends in part on exactly what you want to do, and how many times you're likely to do it (generalized code in separate Sub vs. once in-line). Having your openWorkbook do too much might be an issue: better maybe to have a separate isWorkbookOpen() function for example, since that's pretty useful by itself. – Tim Williams May 22 '16 at 00:28
  • Also - your function take a full path nut only checks open workbooks by name: what it the name-matched workbook is actually not the one you want to open (ie. is on a different path) ? – Tim Williams May 22 '16 at 00:30
  • That's a good point. Well, I better check that possibility too. These all just seem like basic things that would already be built in so I wanted to make sure I wasn't reinventing the wheel or doing something easy in an unecessarily big way – Henrietta Martingale May 22 '16 at 15:24
  • @HenriettaMartingale FWIW the code I supplied in my answer addresses Tim's points and illustrates how proper error handling is done in VBA; not sure what more you're expecting out of answers to this post, feel free to mark it as accepted or to further clarify what's left to answer. – Mathieu Guindon May 22 '16 at 19:04

1 Answers1

3

Your function doesn't declare a return type, so it's implicitly Variant.

You're returning a Boolean False when it fails, and a Workbook object reference when it succeeds. This makes the client code much harder to write than necessary.

Instead, make the function return a Workbook reference, and return Nothing when it fails.

Also, if you supply the default value for your optional parameter in the signature, then your IsMissing check becomes redundant.

Now, I'm not sure why you would need a worksheet name when you're concerned about opening a workbook - especially since, well, you're not doing anything with that worksheetname parameter. Pre-exception error handling in the language isn't the only thing responsible for spaghetti code.

Here's a more sane version:

Public Function OpenWorkbook(ByVal path As String) As Workbook
    On Error GoTo CleanFail

    Dim result As Workbook        
    If Not IsWorkbookOpen(path, result) Then
        Set result = Application.Workbooks.Open(path)
    End If

CleanExit:
    Set OpenWorkbook = result
    Exit Function
CleanFail:
    Set result = Nothing
    Resume CleanExit
End Function

Public Function IsWorkbookOpen(ByVal path As String, Optional ByRef outWorkbook As Workbook = Nothing) As Boolean
    Dim book As Workbook
    For Each book In Application.Workbooks
        If book.FullName = path Then
            IsWorkbookOpen = True
            Set outWorkbook = book
            Exit For
        End If
    Next
End Function

Notice:

  • Explicit Public access modifier
  • Explicit ByVal modifier; your code implicitly passes parameters ByRef but doesn't need to.
  • Explicit and unambiguous return type
  • PascalCase names for public members, to conform with the naming style of every single existing VBA API
  • Separated concerns: verifying whether a workbook is open, vs. opening a workbook
  • Explicit default value for optional parameters
  • Explicit ByRef modifier where appropriate
  • out prefix to denote an "out" parameter
  • Meaningful identifiers everywhere

These aren't "THE" best-practices, they're just how I write VBA. I'm pretty sure having thisIsSoStupid as a variable name in your code is universally seen as unprofessional code though.

Ranting on the "stupid error crap" is fine (I'd much rather deal with exceptions too), but not when your code has unused parameters, ambiguous return types and poor naming.

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
  • Yes, there was a bunch of junk in there because I'm still in mid code and haven't cleaned anything up. 99% of the time I'm in javascript or python and this coding style is foreign. There's some hard coded crap to test, well you know. Anyway I found this, and the answer to another question. to do the if thing, you have to return different things based on what the expected item to return is: – Henrietta Martingale May 22 '16 at 02:44
  • http://stackoverflow.com/questions/3329110/vba-check-if-variable-is-empty. This was GOLD!! There's got to be a cheat sheet somewhere – Henrietta Martingale May 22 '16 at 02:44
  • Finally, sorry all you real vba programmers for the "this is stupid." I wrote it quickly because the equivalent in php is: – Henrietta Martingale May 22 '16 at 02:51
  • return (file_exists($path))? fopen($path, "a+") : false – Henrietta Martingale May 22 '16 at 02:53
  • While VBA supports duck-typing via `Variant`, best practice is to rely on unambiguous, statically typed return values. If your code jumps through hoops to look like php or javascript, then it's not going to look like VBA. Bottom line, it's not because something is *possible* that it's a good idea - *even* in php or javascript. – Mathieu Guindon May 22 '16 at 20:56