Some time ago I was thinking about Interfaces and class inheritance in C# and how hard it can sometimes be to get what you want.
For example, in WPF there are many controls which inherit from Selector: ComboBox, ListBox, ListView, and TabControl. Selector includes SelectedItem and SelectedValue properties as well as a SelectionChanged event.
One notable control missing from the list of Selectors is the TreeView. This control is an ItemsControl but is not a Selector. However, it still has SelectedItem and SelectedValue properties.
The reason why TreeView is not a Selector is that its items don’t have indexes (since they’re hierarchical). Selector includes a SelectedIndex property which wouldn’t make any sense on a TreeView. TreeView also provides a SelectedItemChanged event instead of a SelectionChanged event which includes more information about the change.
Clearly, it makes sense for TreeView not to be a Selector, even though it does have many similar properties. The problem is that there is no common class or interface that TreeView and ListBox (for example) both implement. This means you can’t write common code to accept either a TreeView or a ListBox and get the SelectedValue out of it.
You might need to do this if you were dynamically displaying controls, or creating any kind of framework to work with controls. To accomplish this, you now have to create your own interfaces that describe what you need (SelectedValue, ValueChanged) and then create wrappers for each of the built in controls that implement your interface. Or, you create one big class that knows how to talk to all the different types of controls. I think the first approach is the better one though as it’s easier to maintain and enhance.
This all applies if you’re writing in a static language. If you're writing in a dynamic language, you could just call the SelectedValue property because you know it’s there, and everything would work at run time.
This is just one example of the kinds of problems that are so easy to run into in a statically typed language. To solve these issues, you have to create a lot of boilerplate redundant code that serves no useful purpose. It only increases the size and mental complexity of your code base.
This led me to what I thought was an interesting realization about the difference between statically typed languages and dynamically typed languages.
Static languages don’t trust you. But Dynamic languages do.
In a static language you have to prove to the compiler that the calls you’re making make sense. In a dynamic language, everyone just trusts you to do it right.
But anyone who has ever written any serious code knows that they really can’t be trusted. I mean, I’m going to make mistakes sometimes. And that’s where unit testing comes in.
In a dynamic language the LANGUAGE trusts you completely. Your unit tests on the other hand require you to be correct. The exciting thing here is that your unit tests not only test that the coding details are correct, they also test that your meaning is correct. That makes them much more useful than the compiler alone.
And if we’re going to be writing unit tests in static languages anyway, why be forced to jump through so many hoops convincing the compiler we know what we’re doing? Do we really need to work in a environment that limits our expressive ability because it doesn’t trust us?
I think the idea of using tools (and languages) that trust me (at the same time as they're helping me) and then building my OWN validation/verification specifically for my software is pretty interesting.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.