Ivan Krivyakov's Blog

Premature optimization is the root of all evil

February 5, 2010

IE 8: Where did that tab go?

I am now using Internet Explorer 8 at work (corporate policy), and I noticed that sometimes I cannot find the tabs I open with “open link in new tab”. Firefox always puts new tabs in the right end of the page. This is not very convenient if you have many tabs, but at least I know where to find it.

IE authors appearantly decided to improve on that. A new tab will open immediately to the right of the current tab. But there is a catch. If I open several links in rapid succession, they will appear in the order I open them. I.e.

CURRENT_TAB | LINK1 | LINK2 | LINK3

However, if I pause a little before opening the fourth link, it will appear immediately to the right of the current tab, like this:

CURRENT_TAB | LINK4 | LINK1 | LINK2 | LINK3

It all depends on time between the opening of two links. If I open the links quickly enough one after the other, new link will go to the right of the previous link. If I am not quick enough, new link will go to the right of the current tab.

Since, unlike my computer, I do not have a built-in clock that measures “quickness”, the position of the opened link becomes pretty much random. This is especially annoying if you have many tabs, much more annoying the Firefox. At least it is consistent.

I started with a feeling of general dissatisfaction, such as “why sometimes I cannot find my tabs?”, until I finally took time to reverse engineer their approach.

I imagine IE design team had countless meetings on the subject and this is the compromise solution they arrived to. Frankly, it’s a mess. If I could, I would disable this feature and always have it open new link at the same place, no timers invovled. This way, I at least would no where my tabs went.

January 2, 2010

Ruby

I’ve got a Ruby book “The Ruby Programming Language” by Flanagan and Matsumoto (or should I say the Ruby book?) as a New Year present. I am only starting the reading, so I am going to keep my comments here. This is what I have so far:

- I don’t like the “end” keyword. It is so Pascal :) I would either do away with it altogether, like in Python or come up with something shorter like in C

- I like a lot the embedded expressions for string formatting: "I have #{count} symbols" is so much better than String.Format("I have {0} symbols", count);.

- I am on the fence about “if” and “unless” modifiers that come after the expression, as in
Raise Invalid, "x is too big" unless x<10. It might be closer to the natural language, but overall I don't think this is such a good idea, especially for longer expressions.

- I am somewhat puzzled by the octal notation in the character literals. E.g. "\010" means ASCII character 8. Who uses octal in the 21st century?

December 14, 2009

Scripting .NET Apps

What are the options? This is what I found so far:
* Dynamically compile C# or VB.NET code into an assembly and execute it – I used this route before
* Implement Windows Scripting Host interfaces. Found a couple of links (see below), but no full implementation
* Use DLR
* Use a number of “Script.NET” like projects

Scripting using WSH:
CodeProject: C# interface defintions
DDJ article series on building Active Scripting Host in C#
In particular, part four seems to be of interest.

Unfortunately, there is no ready-to-use download, and it seems like a lot of work. Yes, I am a lazy guy and I have a tight deadline :)

UPD: found 8 year old VB.NET scripting sample ScriptPad from MSDN

December 13, 2009

Poltergeist? No, Vista Data Redirection

As I was working with a Vista machine, I started noticing that occasionally when I make a changes to some files, only certain programs can see them, but others can’t. Most often this happened with files in the “Program Files” directory. It was so weird, that initially I did not believe my eyes. You open a file in console-based FAR manager, and you see one thing. You open it in notepad – completely different thing.

It went on for a while, until the mystery affected an important config file. I spent several hours trying to understand what’s going on, and now it was personal.

It turns out that Vista Vista “virtualizes” write access to otherwise unwritable files in system directories, but it does it in a very peculiar way.

Apparently, Microsoft developers thought along these lines: OK, we must lock down the Program Files and other system directories, but many legacy applications do write their logs to Program Files. We don’t want them to break, do we? So, let’s quietly redirect their failed writes to a safe user-specific location. But of course, we can’t do that for all applications, only for the old ones.

This works, but it creates quite astonishing results. E.g., you legacy claims it created a log file in c:\program files\myapp\important.log. You can smell it, you can feel it, you can even open it inside the application if it has such a capability. But if you go to Windows Explorer or Notepad, the file is simply not there! Poltergeist? No, data redirection. The file is actually in AppData\Local\VirtualStore in your user profile. Windows Explorer and Notepad are obviously designed for Vista, so they see the real, unmodified version of the data.

As far as I understand, all programs are divided into “designed for Vista” and “legacy”. Programs designed for Vista do not require data redirection and thus see the real picture. When legacy programs try to write into an area such as “Program Files” that would fail, this write is redirected to the VirtualStore folder inside user profile. If the write would not fail, it is allowed to go through to “Program Files”. Only locally running programs are redirected.

Thus, it creates a number of astonishing inconsistencies.

  1. The changes made by your application are not visible to system programs, as described above.
  2. The same application sees different data when it runs in elevated “administrator” mode.
  3. If a legacy application accesses modified files via network, it will not see the unmodified data, since no redirection is performed for remote reads.
  4. Only unwritable files are redirected, files writable by non-administrators will be modified in place. If another user looks at the files, he will see some files modified, but not the others.

Furthermore, the config file that started this investigation was in ProgramData directory. This is a new directory in Vista, and no legacy program would write to it. Why data redirection is applied to this directory is yet another mystery.

December 12, 2009

Reading Larman: Iterative Process and “True Path”

Larman says (p. 22) that as the system goes through more iterations it converges “towards final requirements and design” and draws a wavy graph with the size of the waves diminishing with time. My experience seems to disagree with that. As long as the system is “alive” there is no such thing as ‘final requirements’: new features and requests are invented all the time. Occasionally they are just incremental, but frequently they change significant portions of existing functionality.

Reading Larman: to UP or not to UP

I bought Larman’s “Applying UML and Patterns” about a month ago, but had hard time getting to actually read it. This is my first note for a long time – I hope there will be more to follow.

He is promoting the [Rational] Unified Process (UP), but he is quite good in avoiding holy wars. He says (p. 18-19) that the UP is only an example, and you need to use some process to illustrate the techniques. Also, he says that the UP “combines commonly accepted best practices” and that the author “encourages clients to understand and adopt a blend of useful techniques from several methods, rather than a dogmatic ‘my method is better than your method’ mentality”.

This may be just a way to sweet talk opponents and play down the disagreements, but I do like it.

Minimizing Your Virtual PC Hard Drive

Just installed Microsoft Visual Studio 2010 Beta 2 in a virtual PC (Microsoft Virtual PC 2007). It is kinda slow, but it works.

In the process I created two “baseline” images – a “pure” Windows XP install, and the original VS 2010 just after the installation. What I found that the virtual hard drive size may increase considerably as you start using the system. Here’s the algorithm I used to minimize the size of the “baseline” file:

  1. Shut down the virtual PC
  2. Copy virtual hard drive to another file
  3. Edit your virtual PC settings to mount the copy as a second hard drive
  4. Run the virtual PC.
  5. Remove pagefile.sys from the copy. Make sure it does not end up in the recycle bin!
  6. Defragment the copy using Dave Whitney’s defragger (google it if the link is broken).
  7. Using CD menu of the Virtual PC mount “Virtual Disk Precompactor.iso” from “C:\Program Files\Microsoft Virtual PC\Virtual Machine Additions\” on your host system.
  8. The precompactor application by default zeroes out free space on all mounted hard disks. Stop it and use command line options to precompact only the second virtual hard disk.
  9. Shut down your virtual PC.
  10. From Virtual PC Console choose VHD wizard and compact the baseline disk.

These operations may take a while, but it is well worth it – I went from 4+GB image to 1.8GB.

Notwithstanding The Above…

I was downloading C# 4.0 feature list, and Microsoft presented me with a several page license document. Somehow, when I see words “nonwithstanding the above” in a text, I don’t expect anything good to come from it.

December 11, 2009

Public Classes, Protected Methods and Limitations of C# Visibility Control

I had an interesting problem today. I had a public class in my assembly called Session. It was a public class, but it used a lot of internal stuff in the implementation. It went something like this:

public class Session
{
    (public methods and properties here)

    private void HandleResponse(Response response) // Response class is internal
    {
        …
    }
}

Later I needed to split it into two classes: MarketDataSession and TradeSession. They have a lot in common, but they need to handle responses slightly differently. I decided to keep shared functionality in Session making it a base class. So, I modified Session like this:

public class Session
{
    (public methods and properties here)

    protected virtual void HandleResponse(Response response) // Response class is internal
    {
        …
    }
}

public class TradeSession : Session …
public class MarketDataSession : Session …

I immediately ran into trouble: inconsistent accessibility, Response class is less accessible then method HandleResponse. Indeed, HandleResponse is now a protected method of a public class, so theoretically it can be overriden outside of the assembly.

I could make Session an internal class, but public classes TradeSession and MarketDataSession are not allowed to derive from an internal class.

The only solution that allows me to keep Response class internal is to mark HandleResponse method as internal. This makes it invisible from outside of the assembly, but now it is wide open inside the assembly, which is also not so stellar.

There is another, rarely used access control option, protected internal, but it actually means protected OR internal, i.e. the method is accessible to anyone inside the assembly and to derived classes outside of the assembly.

What I need here is protected AND internal: accessible only to derived classes within the same assembly. AFAIK, this option exists in IL and in C++/CLI as private protected . Here’s a real example where it would be useful in C#.

Parsing .NET Enums: some unit tests

Of course, I had to verify that enum parsing really works as they say it does (see previous post). So I wrote a little unit test. All tests in this class pass:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTests
{
    [TestClass]
    public class EnumParsingTest
    {
        enum Test
        {
            Foo = 10,
            Bar = 20
        }

        [TestMethod]
        public void ParseStringValue()
        {
            Assert.AreEqual(Test.Foo, Enum.Parse(typeof(Test), "Foo"));
        }

        [TestMethod]
        public void ParseIntValue()
        {
            Assert.AreEqual(Test.Foo, Enum.Parse(typeof(Test), "10"));
        }

        [TestMethod]
        public void ParseUnrelatedIntValue()
        {
            Assert.AreEqual((Test)40, Enum.Parse(typeof(Test), "40"));
        }

    }
}