Archive for July, 2006

VandalSniper and MonoDevelop

Thursday, July 27th, 2006

Today I decided to try converting my script-based build procedure to a MonoDevelop project. The process was pretty straightforward, although there were some pretty annoying glitches that saw me scrapping the project files several times before it was “just right.”

Now that the conversion is done, my experience with MonoDevelop is so-so. The work that has been done so far is indeed impressive, but I find myself disabling many of the unpolished features simply because they get in my way.

For example, automatic indentation makes assumptions about my coding style that are incorrect, forcing me to re-indent portions of code only to have them butchered again later when I change something. The code parser seems easily confused by things, to the point where it doesn’t recognize half of the members of a class, so I only see a portion of the members in the class browser. Code completion is likewise fragile: it frequently erases code by itself; is unable to find a class in the list after being given a few letters (though I can locate the class in the list it displays); and seems to be constantly using stale data for my own classes, as a Regex field recently changed from a string still displays members of String in the member completion popup.

At this point, MonoDevelop provides very few (if any) benefits over vim and some build scripts. I will continue to watch its progress though — while I don’t find it particularly useful right now, it is a very promising project.

Dvorak

Tuesday, July 11th, 2006

I’ve decided to learn the Dvorak keyboard layout. It’s difficult to adjust, but it’s happening… slowly. I’m using a regular QWERTY keyboard that’s been “converted” with masking tape and a Sharpie.

VandalSniper does the watchlist, yo!

Sunday, July 9th, 2006

It will only be a short while before all of the tabs in VandalSniper are functional! I’ve already implemented the change cache, so the recent changes list is refreshed from the last few edits to be seen on IRC. This makes refreshes instant (except for the diff summary).

Driven by the success of this method, I’ve decided to switch gears with respect to the watchlist tab. Recently I figured out why I was unable to retrieve cookies from the WebControl — it’s document.cookie, not document.cookies. I’ve added yet another parser that, using these cookies, retrieves the articles on the user’s watchlist. This will be stored somewhere, possibly refreshed periodically, and used along the same lines as the sniper tab: if an edit is seen for a watchlisted article, a notification will be displayed and it will be added to the watchlist tab.

A few improvements to the tabbed browsing interface and this is going to be by browser of choice for just browsing Wikipedia!

VandalSniper and IRC: better together!

Saturday, July 8th, 2006

I spent much of the today integrating SmartIrc4net with VandalSniper. No, VandalSniper doesn’t let you chat on IRC now. It connects to the Wikimedia IRC server and joins the Wikipedia “recent changes” channel, which gets spammed by a bot every time any change is made to Wikipedia.

Which means that we can not only save Wikipedia’s bandwidth, but we can update the UI in realtime!

So far the sniper is the only function that uses this live feed. The previous approach has been to go over the “hitlist” in round-robin fashion, checking one user every 5 seconds. This means that if you’re monitoring 6 people, it will take 30 seconds to check everyone! While sluggish, I used this approach to conserve bandwidth and CPU on both ends of the connection. But now, by passively monitoring an IRC channel, the sniper never needs to contact Wikipedia directly, and can display edits in realtime!

Currently the recent changes tab functions as before. I’m still not sure if feeding the IRC stream into the box live is a great idea, as it will be very distracting and won’t give people enough time to check each edit. But I may cache the last 100 or so edits that come out of the stream, and use that cache when refreshing the stream. This would make the refresh immediate, and it wouldn’t require a trip to Special:Recentchanges.

There are only 113 lines in Irc.cs, which is responsible for setting up the IRC connection, converting channel messages into Change objects. and passing these objects off to an event.

Sealed classes in .NET … but why?

Tuesday, July 4th, 2006

While tinkering with C#, I was experimenting with declaring methods “virtual.” This effectively tells subclasses “you can override this method with your own implementation.” After some more tinkering, it seems you can also hide methods that are not declared virtual by prefixing them with “new.” But there is a difference:

using System;

public class A {
    public void method() {
        Console.WriteLine("A.method");
    }
    public virtual void method2() {
        Console.WriteLine("A.method2");
    }
}

public class B : A {
    new public void method() {
        Console.WriteLine("B.method");
    }
    public override void method2() {
        Console.WriteLine("B.method2");
    }
}

The compiler will not complain about this situation. Now pretend that we execute this: B b = new B(); b.method(); b.method2();. We get the output we expect:

B.method
B.method2

Now let’s try A b = new B(); b.method(); b.method2();. See the difference? This time we store the B in an A reference.

A.method
B.method2

Java users will be shocked at this behaviour. But B.method overrides A.method, right?

Wrong. It hides A.method. If we had said A b = new B(); (b as B).method(); we would get the output we expect. This behavior comes directly from C++: if a non-virtual method is “overridden” then which method gets called depends on the reference type used to call it!

This serves two purposes:

  1. If a method is not declared virtual, the CLR doesn’t have to waste time looking for overridden methods on child classes; it can jump directly to the method.
  2. The virtual modifier can be thought of as giving permission to override. If you target a non-virtual method you know it will behave the same way, so long as you are using the same reference type when invoking it.

Which brings me to the question of the day. C# (and any .NET language) supports the notion of a “sealed” class — one that cannot be derived from at all. Immutable classes, such as System.String, are sealed to prevent tampering that could aggravate developers or compromise the entire .NET security architecture.

But what if System.String weren’t sealed? Why, nothing! Almost. Methods overloaded from Object (such as ToString) are implicitly virtual — but if they were marked “sealed” in System.String they are effectively “un-virtualed!” Redefining ToString in a subclass would require “new” and would exhibit the same behavior as the example above. For example:

using System;

public class A {
    public virtual void Foo() {
        Console.WriteLine("A");
    }
}

public class B : A {
    public sealed override void Foo() {
        Console.WriteLine("B");
    }
}

public class C : B {
    new public void Foo() {
        Console.WriteLine("C");
    }
}

public class R {
    public static void Main() {
        C c = new C();
        B b = c;
        A a = b;

        a.Foo();
        b.Foo();
        c.Foo();
    }
}

This outputs the expected:

B
B
C

The benefit of un-sealing these classes is that we could subclass System.String to add our own properties, be able to pass this object around as if it were a string, and not sacrifice the integrity of its immutability. As long as none of System.String’s immutable information is protected or public, we can’t touch it.

Where the system treats it as a string, it is a string. Where we treat it as a subclass, we can extend its behavior how we like.

So why are there sealed classes in .NET? You tell me.