The #develop teamblog
#  Monday, September 01, 2008

Our Wiki has a guideline on joining the team which outlines the process of submitting code to the project. As part of this year's #develop developer days (#d^3) we decided on a change to the guideline:

It is now possible to contribute "any-size" patches (be it a bug fix or feature enhancement) when those code pieces (your changes) are licensed under the BSD license.

Why this change? We want to make it easier for the "accidential contributor" (ie someone who stumbled across a bug and dabbled with our code to fix it) to get her or his changes into our codebase without going through the "hassle" of having to sign & send the JCA. This should lower the barrier to contributing to our project.

If you want to work on a larger feature, we still want you to send us a JCA - the simple reason being in it's name: it is a joint copyright assignment, making you and the project owners to the copyright, allowing you and the project to work with the code in any way desired. For more details on "Why the JCA" please see the guideline.

Categories: Chris
Monday, September 01, 2008 6:12:32 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]

 



#  Friday, August 22, 2008

This addin integrates Microsoft StyleCop into SharpDevelop. StyleCop only supports C#, and this addin has been tested against StyleCop 4.3, earlier versions won't work.

Features

  • Line highlighting of the warnings found
  • Change StyleCop settings on a per-project basis, copying from a master file you can also configure
  • Run as part of the normal build process or on-demand from the project menu

So how do you run StyleCop? Simply from the context menu of the current C# project:

This will result in an error (given that you haven't installed StyleCop yet):

Therefore please download the latest version of StyleCop and install it. Note that you must install the MSBuild integration:

Once installed, you have to tell SharpDevelop where to find it. This is done in the Tools / Options dialog:

Click on "Find StyleCop path" and go to the MSBuild directory:

Now SharpDevelop knows how to find StyleCop, all you have to do is re-run the StyleCop inspection of your project. In my sample project this results in quite a few warnings:

As you might not go d'accord with the default style checks, you can manipulate the StyleCop settings right from your current C# project:

Those rules are documented in StyleCop.

Categories: Chris
Friday, August 22, 2008 8:03:13 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]

 



#  Wednesday, August 20, 2008

Because the question keeps coming up repeatedly in the forum, I want to repeat the most important pieces of advice from the last thread in this blog post. Firstly and most importantly:

If you use SharpDevelop 2.x, you must use TortoiseSVN 1.4.x.
If you use SharpDevelop 3.x, you must use TortoiseSVN 1.5.x.

So why is this important? Well, Subversion 1.5 does change the working copy format, therefore older clients cannot read the working copy anymore. And why is this important to SharpDevelop? Daniel continues to explain:

SharpDevelop uses its own copy of the Subversion library for marking files as added/removed/etc. This can upgrade the working copy to the 1.5 format.

However, SharpDevelop does not have it's own commit dialog - we simply start TortoiseSVN.

So there are two Subversion libraries used by SharpDevelop: the one we ship for local operations, and the one shipped with TortoiseSVN for commit etc. Because the Subversion 1.4 library cannot read working copies touched by the 1.5 library, you run into this kind of problem when either TortoiseSVN or SharpDevelop is too old.

To sum up: SharpDevelop 2.x ships with libraries that are compatible with Subversion 1.4 and requires TortoiseSVN 1.4 for UI. Whereas version 3.0 of SharpDevelop ships with (different) libraries that are compatible with Subversion 1.5 and requires TortoiseSVN 1.5 for UI.

So will there be an upgrade for SharpDevelop 2.x to support Subversion 1.5? This was a hotly debated issue, however, in the end it boiled down to the following question: do we want to ship two almost identical versions of SharpDevelop 2.2 that only differ in the version of the included Subversion library (because we would have to support both camps)? As that would create quite a bit of confusion, we decided to leave 2.2 as is and support Subversion 1.5 only in SharpDevelop 3.0.

Categories: Chris
Wednesday, August 20, 2008 8:01:00 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]

 



#  Tuesday, August 19, 2008

If you receive the following error message

but have TortoiseSVN installed, then you have run into the following snag: SharpDevelop 3.0 is explicity marked as 32 Bit application, thus it cannot use the x64 version of TortoiseSVN.

Solution: install TortoiseSVN 32 Bit. It can be used in parallel with the x64 version.

Categories: Chris
Tuesday, August 19, 2008 9:00:39 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]

 



#  Saturday, August 16, 2008

Running SharpDevelop on USB thumb drives has been possible for a long time. What is new in version 3.0 though is that the settings that usually go into the user's profile can live directly on the memory stick - allowing you to take your settings with you at all times. Here is the procedure:

Download SharpDevelop 3.0 and perform a standard installation on Windows. By default the installation location (on an x64 machine) will be the following:

Simply copy the 3.0 directory to your memory stick, and then open the \bin directory there:

There, you have to open SharpDevelop.exe.config - and search for the appSettings section which by default looks like this:

 <appSettings>
  <!-- Use this configuration setting to store settings in a directory relative to the location
       of SharpDevelop.exe instead of the user's profile directory. -->
  <!-- <add key="settingsPath" value="..\Settings" /> -->
  
  <!-- Use this setting to specify a different path for the code completion cache.
        The cache contains information about referenced assemblies to speed up loading
        the information on future SharpDevelop starts. -->
  <!-- <add key="domPersistencePath" value="..\DomCache" /> -->
  
  <!-- Use this setting to disable the code completion cache. Code completion will still be
       available, but take longer to load and use more RAM. -->
  <!-- <add key="domPersistencePath" value="none" /> -->
 </appSettings>

The comments tell you what to do, basically uncomment settingsPath and domPersistencePath:

<add key="settingsPath" value="..\Settings" />
<add key="domPersistencePath" value="..\DomCache" />

Save the file and you, SharpDevelop and your settings are ready to go. Note that once started the two directories show up in the directory tree:

Categories: Chris
Saturday, August 16, 2008 4:18:14 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]

 



#  Tuesday, April 01, 2008

Starting with version 3.0.0.3010, the C# code completion in SharpDevelop has support for implicitly typed lambda expressions.

Given a variable "IEnumerable<MyClass> items" and the "Select" extension method from LINQ, typing "items.Select(i => i." now shows the members of MyClass. And if the result of the Select call is assigned to an implicitly typed variable, SharpDevelop is now able to infer that the variable has the type IEnumerable<return type of the lambda expression>.

Unlike all other expressions in C#, the type of a lambda expression cannot be inferred just from by at the expression itself (and the variables used by the expression). To resolve lambda type parameters, we also need to look at the context where the lambda is used. Currently, not all contexts are supported by code-completion, you can find the list of known problems in our bugtracker (Component: DOM / Resolver). Should you find anything where code-completion does not work correctly which is not in that list, please file a bug report in our forum.

The most commonly used context for lambda expressions is method calls, and this is also the most difficult thing to support. It's easy when the method has a clear signature like "void M(Func<int, string> f)", since then SharpDevelop can infer the lambda parameter types directly from the delegate type. But most of the time, things aren't that easy. For example, the signature of the Select method is "IEnumerable<R> Select<T, R>(this IEnumerable<T> input, Func<T, R> f)". Here, SharpDevelop needs to first infer what T is, then it can know what the lambda parameter types are, and only after that it can resolve the lambda expression to infer what R is.

But when the method has multiple overloads, things can get even more messy:
When a method has to overloads "void M(Func<string, int> f)" and "void M(Func<int, int> f)", it is valid to call them like this: "F(i=>i.Length)", "F(i=>i+i)". In the first call, i is a string; in the second, it is int. What SharpDevelop needs to do here is to infer the lambda parameter types for each overload separately, infer the lambda's return type; and then check that against the delegate's signature to see which overload was the correct one.

i=>i.Length is a resolve error if i would be int, but returns the expected int if i is string; so i must resolve to string.
i=>i+i returns a string if i would be string, but returns the expected int if i is int; so i must resolve to int.

Note that because there's no way to tell the type of i before the lambda expression is completed, you cannot expect that SharpDevelop gives you correct code completion for it. "Length" will not be included in the code-completion list for i when you type ".", because at that point, the method call is "F(i=>i)", and i is thus an int. But after the expression is written, SharpDevelop will show a tooltip for "Length", and features like "Go to definiton" and "Find references" will work.

Categories: Daniel
Tuesday, April 01, 2008 8:13:48 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]

 



#  Tuesday, March 04, 2008

In addition to our presence on SourceForge (project page) we now also set up shop at CodePlex (project page). The motivation for this step is to increase awareness about SharpDevelop, and how parts of SharpDevelop can be reused in other applications / scenarios.

Categories: Chris
Tuesday, March 04, 2008 11:42:29 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]

 



#  Saturday, January 26, 2008

In SharpDevelop 1.1, the IClass interface had a property that was used in several places in the code:
Once added to a project content, it was immutable. This was not enforced, not even documented. It just happened that no one changed IClass objects except for the code constructing them. After being added to a project content, a class could be removed or replaced by a new version, but if some code still held a reference to an old instance, it could safely access the members without worrying that an update to the class on another thread changed something.

IClass objects are accessed without locks all over the place on the main thread during code completion, and updates on the parser thread should not interfere with that.

However, because I didn't understand this, I broke it in SharpDevelop 2.0. My implementation of partial classes works as following: each file (compilation unit) contributes a part of the class as IClass object representing that part of the class.
Once multiple files register a part of the class in the project content, the project content creates a compound class. This compound class combines the members of all the parts. When updating a part, only the IClass for that part was recreated, and the existing CompoundClass was updated.

The CompoundClass, which could be in use by multiple threads, changed values. To quote Wes Dyer: "Mutation often seems to just cause problems."

Now, that happened to work correctly for quite some time. Most code iterating through a class' members did this with
foreach (IMethod method in c.Methods) {
}

where c is an IClass (possibly a CompoundClass). An update of the compound class happened to recreate the List<IMethod> behind the c.Methods property, so this code continued to work as expected.

However, in the quick class browser (the two combo boxes above the code window), there was code similar to this:
list.AddRange(c.Methods);
list.Sort();
list.AddRange(c.Properties);
list.Sort(c.Methods.Count, c.Properties.Count); // sort the properties without mixing them up with the methods

Suddenly, due to the addition of partial classes, this became a race condition waiting to happen. But it was found in time for the SharpDevelop 2.0 release, and I fixed the crash.
But I didn't know much about immutability back then, so what I did was the worst fix possible:
lock (c) { ... }
And in CompoundClass, during update of the parts: lock (this) { ... }

Now, this is not only bad because it's fixing the symptom instead of the problem and it leaves the possibility for similar problems elsewhere in the code - though it might have been the only instance of the problem, since no other crashes due to this have been found while SharpDevelop was using the fix (all 2.x releases use it, including the current stable release, SharpDevelop 2.2.1).

But multi-threading (without immutability) is not hard, it's really, really hard. So it's not really surprising that some day, I found this code to deadlock.

So where's the deadlock?
First I must tell you the other lock we're colliding with: every project content has a lock that it uses to ensure that GetClass() calls are not happening concurrently when the list of classes is updated. So the parser thread acquires the project content lock and then the CompoundClass lock to update the CompoundClass.

But why would the AddRange / Sort code deadlock with this? The comparer used for list.Sort() sorts the members alphabetically using their language-specific conversion to string. In the case of methods, this includes the parameter list, including the parameter types.

What you need to know here is that type references (IReturnType objects) are not immutable - they need to always reference the newest version of the class, as we cannot afford rebuilding all IReturnType objects from all classes in the solution whenever any class changes. Now remember that C# allows code like "using Alias = System.String; class Test { void Method(Alias parameter) {} }".

In this case, the quick class browser correctly resolves the alias and reports "Method(string parameter)". This means that our Sort() call actually sometimes needs to resolve types! And resolving types works using IProjectContent.SearchType, which locks on the project contents' class list lock. And that's our deadlock.

I think it's near impossible to find this kind of deadlock until it occurs and you can see the call stacks of the two blocked threads.
Remember that the actual Method->string conversion and the type resolving is language-specific; it may or may not happen to take a lock for other language binding AddIns.

I fixed the deadlock on trunk (SharpDevelop 3.0) a few months ago by removing the lock on CompoundClass and instead doing this:
list.AddRange(c.Methods);
list.Sort();
int count = list.Count;
list.AddRange(c.Properties);
list.Sort(count, list.Count - count);

It's still a hack, but this doesn't have any side effects (like taking a lock). And it works correctly under our (new) rule (undocumented rule, aka. assumption) that multiple c.get_Methods calls may return different collections, but the collection's contents don't change.

"foreach (IMethod method in c.Methods) { ... }" is safe, but "for (int i = 0; i < c.Methods.Count; i++) { IMethod method = c.Methods[i]; ... }" can crash.

But that's quite a difficult rule compared to "IClass never changes". So after reading Erip Lippert's series on immutability, I finally decided to make IClass immutable again.

It's "popsicle immutability", that means IClass instances are mutable, but when the Freeze() method is called, they become immutable. And this time, immutability is enforced, trying to change a property of a frozen IClass will cause an exception. Adding an IClass to a project content will cause it to freeze if it isn’t already frozen, so it's guaranteed that IClass objects returned by GetClass or by some type reference are immutable.

Categories: Daniel
Saturday, January 26, 2008 11:30:59 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]

 



#  Wednesday, January 23, 2008

A change that happened rather early in the development process of SharpDevelop 3.0 (revision 2658, 8/13/2007) was that we replaced NDoc (a stalled open source project) with Sandcastle Help File Builder (SHFB). SHFB looks and feels similar to NDoc, however, it builds on top of Sandcastle, a documentation generation tool by Microsoft.

Our build server (revision 2913 and higher) contains SHFB 1.6.0.4, which itself builds on top of the January 2008 release of Sandcastle (both are at the moment the latest releases of their respective projects). SharpDevelop 3.0 setup ships with SHFB, however, Sandcastle itself does not and must be installed separately! (this might change in the future once the final license of Sandcastle is known)

Because of the regular releases of Sandcastle and SHFB, the distribution of SharpDevelop 3.0 might ship with older versions of SHFB than currently available for download. Thanks to Eric Woodruff, the maintainer of SHFB, this is not a big deal - he is offering a download specific for SharpDevelop:

All you have to do is first delete the contents of the following installation directory (including subdirectories):

Then simply unzip the SHFB distribution archive into this folder and presto - you are now using the latest version of SHFB from inside SharpDevelop!

Categories: Chris
Wednesday, January 23, 2008 8:40:44 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]

 



#  Tuesday, January 15, 2008

This question came up for example in the thread SharpDev 2.2.x on BuilderServer (this thread was started because we ceased to automatically build v2.2 on 1/11/2008).

The answer is Yes. Development of SharpDevelop 2.2 stopped with revision 2675 (8/28/2007), which is three revisions higher than the officially shipping version of SharpDevelop 2.2 (Download, 8/8/2007). The three non-shipping commits are:

  • 2673: Improved CSharpCodeCompletion sample: add tool tip support, show only one entry for overloaded methods
  • 2674: Fixed some off-by-one bugs in the CSharpCodeCompletion example (caused by the different line counting in the parser and the text editor).
  • 2675: CSharpCodeCompletionSample: show xml documentation

All three were (of course) merged into Montferrer (SharpDevelop 3.0), this merge happened in revision 2679. However, those commits did not merit a release of a new setup because those were all changes to a sample shipping only in the source download.

Since releasing v2.2.1 all work stopped on the 2.x series of SharpDevelop. Our efforts went (and still go) into SharpDevelop 3.

Categories: Chris
Tuesday, January 15, 2008 10:37:39 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]

 



© Copyright 2014 SharpDevelop Core Team

Subscribe to this weblog's RSS feed with SharpReader, Radio Userland, NewsGator or any other aggregator listening on port 5335 by clicking this button.   RSS 2.0|Atom 1.0  Send mail to the author(s)

 

Copyright ©2000-2009 IC#Code. All rights reserved. Projects sponsored by AlphaSierraPapa.