There is more than one way to linq that

Eric Gunnerson has a post in which he responds to Justin Etheredge regarding “Is Programming A Generic Skill?

I’ll just say that I agree with them both. There are differences between ability, proficiency and mastery.

A Java programmer can jump into C# and be an able C# programmer immediately. It will take time to become proficient and even more time to develop mastery.

I am proof of this with python. I’ve been an able python programmer for over 10 years now(actually closer to 15), but I never spent enough time in python to call myself proficient and I’m certainly far from a master.

But the thing that Eric said which triggered me to write this is not the generic skill discussion with Justin, it is instead a remark that Eric said about Perl, “… because of TMTOWTDI”.

C# is very much becoming afflicted with There is More Than One Way To Do It. It certainly is both the language and library.

Consider LINQ. LINQ to Objects is a new way to do something which everyone has done differently in the past. When new programmers are exposed to linq, I often hear the question “When do I use linq?” The answer I give is typically “whenever you would use a for loop or foreach loop and if you can’t, figure out how you can".

If we throw away the ‘idiomatic code” to which Eric refers, then a giant bucket of TMTOWTDI is thrown in our face. Do we use properties or fields, events or delegate fields?

For public interfaces, FxCop helps a great deal with guidelines for these things and helping to learn the idioms of the language and framework, but for other things, you are left to yourself. That is why reading others source code is so important. (see the weekly course code)

Expand into libraries and TMTOWTDI explodes. From MSFT alone there is Remoting, Web Services (asmx), WSE, WCF, RIA Services, ASHX, ASP.NET Data Services, all of which have some overlap. Then for data access there is ADO.NET, Linq2Sql, Entity Framework. Even within ADO.NET alone, TMTOWTDI. Do you use a reader? Table Adapter with DataSets? Strongly Typed DataSets?

Open to non MSFT and TMTOWTDI explodes again, to the point where I won’t bother listing anything. There is too much.

I think that library TMTOWTDI will always exist. Even Python has SqlObject, SqlAlchemy and ORM as parts of other frameworks like Zope and Django. But language TMTOWTDI is reasonably well mitigated in Python. This is stated in a single line in PEP20 – The Zen of Python

There should be one—preferably only one –obvious way to do it.

C#, perhaps because it was not a goal and because of its C/Java/Delphi roots, has never had that. There has always been TMTOWTDI in C#.

How useful are your error messages?

F.cs(334,8): error CS0539: ‘I.M’ in explicit interface declaration is not a member of interface
F.cs(20,15): error CS0535: ‘C’ does not implement interface member ‘I.M(out string)’

This is a fun example of a poor error message, and I don’t mean because I named my file F, my interface I, my method M and my class C.

Its poor because the underlying code looks like this:

interface I { bool M(out string); }

class C:I { void M(out string); }

Sure, this is obvious now what is going on, I have void, but I should have bool, but my error message doesn’t include that when it shows the type signature.  Now consider what happens when interface I is in an assembly which is given to me. I do not have its source, and there is no documentation. My means of finding the signature of this method are three fold:

  1. lean on visual studio press F12 to go to reference of the interface and VS shows me type signatures
  2. use reflector
  3. monodis mylibrary | grep MethodName

I usually use #1, which is probably why I’ve never seen how horrible this compiler error message is until today. Today, I used #3.

* monodis is from Mono

Browsing NHibernate Source Can Be Beautiful

NHibernate is awesome, but when Oren’s blog doesn’t have for what you are looking, and your google-fu is coming up short, it can be challenging to find what you want.

http://nhforge.org – is excellent, but almost never comes up in google searches.

http://nhibernate.sf.net – the sourceforge page redirects to http://nhibernate.org which in turn redirects to the http://hibernate.org nhibernate area.

I often want to browse the source. I just need to quickly see what they have done, and I don’t want to open the nhibernate sln on my system.

http://nhibernate.svn.sourceforge.net/viewvc/nhibernate/

I had to hunt around for more than a minute, to find the above url, but rest assured, it is viewvc pointed to nhibernate svn hosted by sourceforge.

If you can’t tell, I love viewvc.

TechEd 2009

I’m leaving tomorrow to go to TechEd 2009. I’ll be working the C# and F# “Ask The Experts” booths for half of the day each day Monday through Thursday. When I’m not there, I’ll be catching sessions and pretending to be an open sourcer by hanging in the Mono booth.

If you want to meet, or just say hi, stop by and do so!

RegexReplace in SQL Server

My last post was about SQL Server. Even 10+ years later, I’m continually amazed by features which are daily use features in MySQL and Postgresql which are missing from MS SQL Server.

Regular expression matching and replacing is a severely lacking feature.

Sql Server 2005 introduced a means to write user defined functions in .NET code, so this method is uploaded to a sql server and exposed as a function.

[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString RegexReplace(SqlString input, SqlString pattern, SqlString replacement)
{
    var result = System.Text.RegularExpressions.Regex.Replace(input.Value, pattern.Value, replacement.Value);
    return new SqlString(result);
}

 

Now you can use it in select statements.

SELECT        Name, dbo.RegexReplace(Name, N'(?:\d+-)?\d+PPM’, N”) AS e
FROM            Table2

 

Or use it to update tables

update table2 set name=dbo.RegexReplace(Name, N'(?:\d+-)?\d+PPM’, N”)

 

I have absolutely no idea how any database developer could live without this kind of functionality.

ASP.NET via Mono and Apache

In my last post I showed how to build Mono trunk on the latest Ubuntu. I pointed out that I am using it on a “server” install of Ubuntu. I don’t have GTK+ or GTK# installed. So what good is Mono? Its good for hosting ASP.NET web applications.

  1. Configure an apache development environment.
    sudo apt-get install apache2-prefork-dev
  2. Grab my mono-dev-update script and tell it to only do mod_mono
    curl http://jrwren.wrenfam.com/scripts/mono-dev-update
    ./mono-dev-update –m mod_mono
  3. Install the apache module
    pushd /opt/mono/src/mod_mono ; sudo make install ; popd
  4. Enable the apache module
    pushd /etc/apache2/mods-enabled;ln –s ../mod_mono.conf . ; popd
  5. Restart Apache
    sudo /etc/init.d/apache2 restart
  6. Test it
    echo ’<%=DateTime.Now%>’ |sudo tee /var/www/index.aspx
    curl localhost/index.aspx

You should see the current date and time displayed. If you don’t, you have done something wrong.  Note that quotes paste poorly out of wordpress, so you may need to type out some of these commands.

Mono trunk on Ubuntu Jaunty

With the release of Ubuntu 9.04 aka Jaunty later this month, I thought I’d share how to get a current version of Mono on the latest Ubuntu release.

For a number of reasons, Ubuntu always seems to be just a little behind current with its Mono packages. The largest reason IMO is the difficulty in properly packaging Mono for Debian/Ubuntu. I’ve tried and it is not easy.

  1. Make our install a tiny developer environment.
    sudo apt-get install build-essential subversion autoconf libtool bison gettext pkg-config libglib2.0-dev
  2. Install the old Mono 2.0 C# compiler from jaunty so that we can bootstrap the trunk compiler.
    sudo apt-get install mono-mcs
    ln –s /usr/bin/mcs1 /usr/bin/mcs
    This installs enough mono to let the C# compiler run. We will remove this and all its dependencies later.
  3. Fetch the source from SVN. I use a mono-dev-update script to checkout the first time and keep me updated. The script pulls and installs mono, mcs, xsp to /opt/mono on a default ubuntu server install once step 1 above has been performed. To build more parts of mono such as GTK# and MonoDevelop you will need more gtk+ library dependencies.
    sudo mkdir –p /opt/mono/src
    sudo chown $USER /opt/mono /opt/mono/src
    ./mono-dev-update
  4. Remove the bootstrap mcs
    sudo apt-get remove binfmt-support cli-common libmono-corlib1.0-cil libmono-corlib2.0-cil libmono-i18n1.0-cil libmono-i18n2.0-cil libmono-security2.0-cil libmono-system1.0-cil libmono-system2.0-cil libmono0 mono-2.0-gac mono-2.0-runtime mono-common mono-gac mono-jit mono-mcs mono-runtime

The real work is done by the mono-dev-update script. Its a mess of bash script which has served me well for a couple of years now.

I’ll paste the current version of it here, but I’ll also try to keep it up to date for download here.

#!/bin/bash
#mono-dev-update
#Jay R. Wren <jrwren@xmtp.net>
#usage:
#   -s      skip svn operations. don't try to pull updates.
#   -f      force autogen.sh or configure to run.
#   -l n    set build level to value of 'n'. This controls optional package 
#           builds. Not used much
#   -n      no auto retry. if make fails, do not try to ./configure and 
#           make again.

MONO_PREFIX=/opt/mono
#GNOME_PREFIX=/opt/gnome
GNOME_PREFIX=/usr
export LD_LIBRARY_PATH=$MONO_PREFIX/lib:$LD_LIBRARY_PATH
export C_INCLUDE_PATH=$MONO_PREFIX/include:$GNOME_PREFIX/include
export ACLOCAL_PATH=$MONO_PREFIX/share/aclocal
export PKG_CONFIG_PATH=$MONO_PREFIX/lib/pkgconfig:$GNOME_PREFIX/lib/pkgconfig
PATH=$MONO_PREFIX/bin:$PATH
export MANPATH=$MANPATH:$MONO_PREFIX/share/man
if [[ ! -d $MONO_PREFIX/src ]];then mkdir $MONO_PREFIX/src; fi
pushd $MONO_PREFIX/src

SVNDIRS="mcs mono xsp monodevelop gtk-sharp gtkmozembed-sharp type-reflector debugger banshee-sample-plugin olive mono-tools" 
CVSDIRS="banshee"
MAKEDIRS="mono xsp debugger mono-tools monodevelop gtkmozembed-sharp "
BANSCHEEPLUGINS="banshee-sample-plugin" 

level=0
skipsvn=0

optCount=0;
while getopts :xvfsnd:t:cl:m: OPTS ;do
	if [[ $OPTS == "x" ]]; then outputStyle=xml ; optCount=$((optCount+1)) ; fi
	if [[ $OPTS == "v" ]]; then action=view ; optCount=$((optCount+1)) ; fi
	if [[ $OPTS == "f" ]]; then forceAGen="true" ; optCount=$((optCount+1)) ; fi
	if [[ $OPTS == "s" ]]; then skipsvn=1 ; optCount=$((optCount+1)) ; fi
	if [[ $OPTS == "n" ]]; then noautoretry="true" ; optCount=$((optCount+1)) ; fi
	if [[ $OPTS == "d" ]]; then DEBUG="$OPTARG" ; optCount=$((optCount+2)) ; fi
	if [[ $OPTS == "t" ]]; then transform="$OPTARG" ; optCount=$((optCount+2)) ; fi
	if [[ $OPTS == "c" ]]; then for i in $MAKEDIRS;do pushd $i ; make clean ; popd ; done ;exit ; optCount=$((optCount+1)) ; fi
	if [[ $OPTS == "l" ]]; then level="$OPTARG" ; optCount=$((optCount+2)) ; fi
	if [[ $OPTS == "m" ]]; then MAKEDIRS="$OPTARG" ; optCount=$((optCount+2));fi
done
if [[ $optCount != $((OPTIND-1)) ]] ; then echo "optcount($optCount) not equal to OPTIND($OPTIND)";fi

echo "using makedirs $MAKEDIRS"

echo "using prefix $MONO_PREFIX"

if [[ 1 > $skipsvn ]]; then
for i in $SVNDIRS
do
	echo -e "\e[1;31m pushd $i \e[m"
	if [[ -d $i ]];then
		pushd $i 
        if [[ ! -d .svn ]];then pushd .. ; svn co http://anonsvn.mono-project.com/source/trunk/$i ;popd; fi
		echo -e "\e[1;31m svn info"
		svn info
		echo 'svn log -r `svn info|grep Revision|cut -f2 -d' '`:HEAD'
		echo -e "\e[m"
		svn log -r `svn info|grep Revision|cut -f2 -d' '`:HEAD
		echo svn up
		nice -n 20 svn up 
		if [ $? != 0 ]; then echo "ERROR: $?" ;popd ; break; fi
		pwd
		popd
	fi
done
else
	echo "-s detected, skipping svn update"
fi 


#mono, xsp, MD, GTK# etc
function autogenAndMake () {
	echo "running for $*"
	for i in $*
	do
		if [[ -d $i ]]; then
			echo -e "\e[1;31m pushd $i \e[m"
			pushd $i 
			if [[ -f "autogen.sh" ]];then
				PROG=./autogen.sh
			else
				PROG=./configure
			fi
			if [[ "true" != $forceAGen ]]; then
				nice -n 20 make && nice -n 20 make install  
			fi

			if [[ "true" != $noautoretry && $? != 0 || "true" == $forceAGen ]]; then 
				echo -e "\e[1;31m "
				echo 'make clean ; $PROG --prefix=$MONO_PREFIX --enable-aspnet --enable-aspnetedit --with-preview --with-moonlight && nice -n 20 make && nice -n 20 make install'
				echo -e "\e[m"
				if [[ -f Makefile ]]; then make clean; fi
				$PROG --prefix=$MONO_PREFIX --enable-aspnet --enable-aspnetedit --with-preview --with-moonlight && nice -n 20 make && nice -n 20 make install || break
			fi
			popd 
		fi
	done 
}

#-l not  speced or even means build all - odd means build only banshee & olive
if [[ $((level % 2)) == 0 ]]; then 
autogenAndMake $MAKEDIRS
fi

if [[ $level > 1 ]]; then
	i=gtk-sharp
			echo -e "\e[1;31m pushd $i \e[m"
			pushd $i
			echo -e "\e[1;31m "
			echo 'make clean ; ./bootstrap-2.12 --prefix=$MONO_PREFIX  && nice -n 20 make && nice -n 20 make install'
			echo -e "\e[m"
			if [[ -f Makefile ]]; then make clean ; fi
			./bootstrap-2.12 --prefix=$MONO_PREFIX  && nice -n 20 make && nice -n 20 make install || break
	popd
fi

if [[ $level > 1 ]];then
	#olive
	for i in olive 
	do 
		if [[ -d $i ]] ; then
			echo -e "\e[1;31m pushd $i \e[m"
			pushd $i
			echo -e "\e[1;31m "
			echo 'make clean ; ./configure  --prefix=$MONO_PREFIX  && nice -n 20 make && nice -n 20 make install'
			echo -e "\e[m"
			if [[ -f Makefile ]]; then make clean ; fi
			./configure  --prefix=$MONO_PREFIX  && nice -n 20 make && nice -n 20 make install || break
			popd
		fi
	done
fi

if [[ $level > 1 ]];then
	#banshee
	if [[ -d banshee ]];then
	pushd banshee
		cvs up
		./configure --prefix=$MONO_PREFIX --disable-helix && nice -n 20 make && nice -n 20 make install || break
	popd
	autogenAndMake $BANSCHEEPLUGINS
	fi
fi

popd

Don’t mix ANY and x86 build and forget about it

you will get a very stupid error like this:

System.BadImageFormatException : Could not load file or assembly or one of its dependencies. An attempt was made to load a program with an incorrect format.

In my case, I was getting it in a TestFixtureSetUp method.

DUH. I had set the class library project to force to x86, because I’m on x64, but I wanted to use edit and continue. I never changed the Test project, so it was still running x64. It failed with a “BadImageFormatException” when it loaded the references x86 project.

Don’t be stupid like me.