API's that Suck

December 17, 2009

Conjecture: Oracle is Building a MySQL Backend that Targets Oracle Database

Filed under: Uncategorized — Grauenwolf @ 2:03 am

Ok, so here are my facts and assumptions

  • MySQL is the most popular choice for small websites that need a database backend.
  • Unless you have a ton of development resources devoted just to customizing MySQL, eventually those sites are going to outgrow the MySQL.
  • All the major database companies (Microsoft, Oracle, and IBM) would love to offer an upgrade path to their produce.
  • MySQL’s Pluggable Storage Engine, with or without some rework, can support these database servers.
  • MySQL’s Pluggable Storage Engine can only be used if you are willing to offer GPL code.
  • Microsoft, Oracle, and IBM are not going to release key components under the GPL.

New facts from Oracle’s Press Release

1. Continued Availability of Storage Engine APIs. Oracle shall maintain and periodically enhance MySQL’s Pluggable Storage Engine Architecture to allow users the flexibility to choose from a portfolio of native and third party supplied storage engines.

MySQL’s Pluggable Storage Engine Architecture shall mean MySQL’s current practice of using, publicly-available, documented application programming interfaces to allow storage engine vendors to "plug" into the MySQL database server. Documentation shall be consistent with the documentation currently provided by Sun.

2. Non-assertion. As copyright holder, Oracle will change Sun’s current policy and shall not assert or threaten to assert against anyone that a third party vendor’s implementations of storage engines must be released under the GPL because they have implemented the application programming interfaces available as part of MySQL’s Pluggable Storage Engine Architecture.

A commercial license will not be required by Oracle from third party storage engine vendors in order to implement the application programming interfaces available as part of MySQL’s Pluggable Storage Engine Architecture.

Oracle shall reproduce this commitment in contractual commitments to storage vendors who at present have a commercial license with Sun.

That pretty much knocks off all the major roadblocks between the big three database and MySQL. With Oracle taking ownership of MySQL, they technically don’t need to lift the GPL restrictions on plug-ins. But by doing do they legitimize their plans to offer an Oracle backend and fend off any possible anti-trust disputes.

December 13, 2009

Sometimes Errors Don’t Matter

Filed under: Uncategorized — Grauenwolf @ 2:37 am

I have, on countless occasions, cursed the existence of “On Error Resume Next”. Why in god’s name did Microsoft see fit to include that abomination in very variant of Visual Basic is beyond me. Even VB 10 has it.

Then I needed to write a script. Just a simple loop that would download images from a web site. On the first pass it bombed because, of course, there were some images that didn’t exist. I thought about adding a simple try-catch block, then something else struck me. Sometimes errors don’t matter. Sometimes you can just keep on barreling on through without caring  what did or didn’t work because ultimately it doesn’t matter.

  1. On Error Resume Next
  2.  
  3. Dim sourcePattern = "http://www.thearma.org/Manuals/{0}.jpg"
  4. Dim targetFolder = "C:\Users\Grauenwolf\Documents\Fencing\Codex Wallerstein\ARMA Scans"
  5.  
  6. For i = 10 To 222
  7.     Dim target = IO.Path.Combine(targetFolder, i & ".jpg")
  8.     Dim source = String.Format(sourcePattern, i)
  9.     If Not IO.File.Exists(target) Then
  10.         Console.WriteLine("Downloading " & source)
  11.         My.Computer.Network.DownloadFile(source, target)
  12.     End If
  13. Next
  14. Console.WriteLine("done")

December 10, 2009

Did you know overload resolution is broken in C#?

Filed under: Uncategorized — Grauenwolf @ 10:52 pm

Lets say you have this code:

  1. class Program
  2. {
  3.     static void Main()
  4.     {
  5.         Foo(new Giraffe());
  6.     }
  7.     static void Foo(Animal animal) { }
  8. }
  9.  
  10. class Animal { }
  11. class Mammal : Animal { }
  12. class Giraffe : Mammal { }
  13. class Reptile : Animal { }

So far so good. Now someone comes along and adds an overload to Foo specifically for Reptiles.

  1. static void Foo<T>(T t) where T : Reptile { }

What should happen? Well since Foo<T>(T) isn’t a viable candidate, it should continue to use Foo(Animal).

What actually happens is you get this error message.

The type ‘ConsoleApplication2.Giraffe’ cannot be used as type parameter ‘T’ in the generic type or method ‘ConsoleApplication2.Program.Foo<T>(T)’. There is no implicit reference conversion from ‘ConsoleApplication2.Giraffe’ to ‘ConsoleApplication2.Reptile’.

Eric Lippert tells us that the “constraints are not part of the signature”, which is of course easily verifiable. But then he goes on to say C# is correct in throwing a compiler error in this scenario because that’s what the C# specification says that it should do.

Lets see the same code in Visual Basic:

  1. Module Module1
  2.  
  3.     Sub Main()
  4.         Foo(New Giraffe)
  5.     End Sub
  6.  
  7.     Sub Foo(Of T As Reptile)(ByVal argt As T)
  8.     End Sub
  9.  
  10.     Sub Foo(ByVal animal As Animal)
  11.     End Sub
  12.  
  13. End Module
  14.  
  15. Class Animal : End Class
  16. Class Mammal : Inherits Animal : End Class
  17. Class Giraffe : Inherits Mammal : End Class
  18. Class Reptile : Inherits Animal : End Class

No errors here.

So yea, the C# compiler’s overload resolution code is broken. It may match the specification, but unless someone can come up with a really good reason for that behavior it just means the specification is also broken.

EDIT:

By the way, you can fix the C# code by explicit casting.

  1. Foo((Animal)new Giraffe());

Three sets of parens to VB’s one, that sounds about right.

December 8, 2009

Why I like the dictionary operator

Filed under: Uncategorized — Grauenwolf @ 11:48 pm

Before

 

  1. currentRow("IBD") = GetS(line, 1, 3)
  2. '4 is not needed
  3. currentRow("TradeDate") = GetD8(line, 5, 12)
  4. currentRow("RefNumber") = GetS(line, 13, 18)
  5. currentRow("OfficeNumber") = GetS(line, 19, 21)
  6. currentRow("AccountNumber") = GetS(line, 22, 30)
  7. currentRow("AccountType") = GetS(line, 31, 31)
  8. currentRow("AccountName") = GetS(line, 32, 63)
  9. currentRow("BuySellCode") = GetS(line, 64, 64)
  10. currentRow("CancelCode") = GetS(line, 65, 65)
  11. currentRow("CapsSource") = GetS(line, 66, 68)
  12. currentRow("Quantity") = GetD(line, 69, 81, 4)
  13. currentRow("Price") = GetD(line, 82, 94, 7)
  14. currentRow("ProductCode") = GetS(line, 95, 98)
  15. currentRow("Cusip") = GetS(line, 99, 107)
  16. currentRow("AccountShortName") = GetS(line, 108, 117)
  17. currentRow("OrderType") = GetS(line, 118, 118)
  18. currentRow("MiscFee") = GetD(line, 119, 131, 2)
  19. '132-133 is not needed

 

After

 

  1. With currentRow
  2.     !IBD = GetS(line, 1, 3)
  3.     '4 is not needed
  4.     !TradeDate = GetD8(line, 5, 12)
  5.     !RefNumber = GetS(line, 13, 18)
  6.     !OfficeNumber = GetS(line, 19, 21)
  7.     !AccountNumber = GetS(line, 22, 30)
  8.     !AccountType = GetS(line, 31, 31)
  9.     !AccountName = GetS(line, 32, 63)
  10.     !BuySellCode = GetS(line, 64, 64)
  11.     !CancelCode = GetS(line, 65, 65)
  12.     !CapsSource = GetS(line, 66, 68)
  13.     !Quantity = GetD(line, 69, 81, 4)
  14.     !Price = GetD(line, 82, 94, 7)
  15.     !ProductCode = GetS(line, 95, 98)
  16.     !Cusip = GetS(line, 99, 107)
  17.     !AccountShortName = GetS(line, 108, 117)
  18.     !OrderType = GetS(line, 118, 118)
  19.     !MiscFee = GetD(line, 119, 131, 2)
  20.     '132-133 is not needed
  21. End With

My only problem is that late-bound identifiers like column names should be colored differently than ones that are statically verified.

December 2, 2009

Why closures are important to GUI developers

Filed under: Uncategorized — Grauenwolf @ 9:51 pm

Lets say you have some code that calls the database and processes the results. Here is a simple in-line version.

  1. private void PerformDataBaseSearch()
  2. {
  3.     m_Progress.Visibility = Visibility.Visible;
  4.     m_SearchButton.IsEnabled = false;
  5.  
  6.     var errorKey = (MPSPortfolioProcessErrorType)m_ErrorTypeSearchBox.SelectedItem;
  7.     var accountNumber = this.m_AccountSearchBox.Text;
  8.  
  9.     List<MpsPortfolioError> resultList = null;
  10.  
  11.     try
  12.     {
  13.         resultList = MpsPortfolioError.Search(Context.FisDatamapper, errorKey, accountNumber);
  14.         InternalControlSetup(resultList);
  15.     }
  16.     catch (Exception ex)
  17.     {
  18.         Context.Logger.DisplayException(ex, "Email Error Search has failed.");
  19.     }
  20.     m_Progress.Visibility = Visibility.Hidden;
  21.     m_SearchButton.IsEnabled = true;
  22.  
  23. }

Since they touch the user interface, Lines 3 thru 7 and 14-21 have to be executed on the GUI thread. Line 13, which actually calls the database, shouldn’t be on the GUI. Normally the way we would fix this is to break up the function into three separate functions using threads and invokes to control where each part gets executed. In earlier versions of C# this was quite tedious and somewhat error prone.

With closures, this becomes downright simple.

  1. private void PerformDataBaseSearchAsynch()
  2. {
  3.     m_Progress.Visibility = Visibility.Visible;
  4.     m_SearchButton.IsEnabled = false;
  5.  
  6.     var errorKey = (MPSPortfolioProcessErrorType)m_ErrorTypeSearchBox.SelectedItem;
  7.     var accountNumber = this.m_AccountSearchBox.Text;
  8.  
  9.     List<MpsPortfolioError> resultList = null;
  10.  
  11.     var asyncSearch = new BackgroundWorker();
  12.     asyncSearch.DoWork += (arg1, arg2) =>
  13.         {
  14.             resultList = MpsPortfolioError.Search(Context.FisDatamapper, errorKey, accountNumber);
  15.         };
  16.  
  17.     asyncSearch.RunWorkerCompleted += (arg1, arg2) =>
  18.         {
  19.             if (arg2.Error == null)
  20.                 InternalControlSetup(resultList);
  21.             else
  22.                 Context.Logger.DisplayException(arg2.Error, "Email Error Search has failed.");
  23.             m_Progress.Visibility = Visibility.Hidden;
  24.             m_SearchButton.IsEnabled = true;
  25.         };
  26.  
  27.     asyncSearch.RunWorkerAsync();
  28. }

Here is how to read the new breakdown of the function.

  • Lines 1 thru 11 haven’t changed, they all run synchronously on your GUI thread.
  • Lines 12 thru 15 define an anonymous function that will run asynchronously on a background thread.
  • Lines 17 thru 25 define an anonymous function that will run asynchronously on the GUI thread, once the background thread is done.
  • Line 27 says all the asynchronous functions have been defined and processing can begin.

Now that I’ve shown you how anonymous functions can be used to keep the logical flow of a procedure while the physical flow is broken up into threads, lets talk about closures themselves. We use one closure in this, the resultList variable. It is defined in the synchronously function, set by the background function, and read by the asynchronous GUI function. All three functions get access to this variable, but nothing else does so we don’t have to worry about synchronization.

Blog at WordPress.com.