Naturally, as we write programs we create a small set of useful functions. BASeBlock has been no exception. I’ve created quite a few functions that offer generic functionality that could be used elsewhere. Here, I share some of them.
Clamping values is a very common activity. It started to get on my nerves, repeating code to make sure a given value was within a range. As a result I conceived of a generic function that could be used for any IComparable.
The basic idea is fairly simple. First, in order to clamp the value, we will need to be able to compare them, so we constrain the function to accepting only type T’s that implement that interface. The first step is casting each value to an IComparable; then we use those variables to compare and return the appropriate value. if the value is larger than max, max is returned; if it is smaller than min, min is returned. otherwise, value is returned unchanged. This function is most useful for numbers, but it can also have interesting implications and usage cases for other classes that are comparable, even strings.
This also came up quite a lot- some parts of the game needed to randomly choose some set of values from a larger set of values. Naturally this gave birth to another generic routine for the purpose:
The idea is simple- make a SortedList that sorts the given listing using a random value as a key, then take the top numselect items off the top. This code will not work properly if numselect is larger than the size of the enumeration, but using count to clamp the size of the array would enumerate twice.
It’s probably possible to make this faster- possibly much faster- since we only need numselect elements. The core idea here is to shuffle the input array and choose two elements. One flawed approach for shuffling an array is to choose a random index and swap it with another random index, but this has myriad problems since it doesn’t really guarantee that everything is shuffled, and the result could very well have runs of the original card order.
Now, what if we had three objects we wanted to randomly choose from, and we wanted one of them to be chosen more frequently? One way of doing this is to use the above choose function and add duplicate entries. However, this could be tricky if you had odd requirements. This is where the Select<T> function would come in. this function is designed to accept an array and a corresponding array of probability weightings; if all the weightings are equal, than the result should be similar to what we get from Choose. Select accomplishes this by keeping it simple. each array element is essentially assigned a given range within the total, and a random number is generated from the complete total of all weightings. For example, if we had the following elements:
| # | Name | Weight |
|---|---|---|
| 1 | Billy | 15 |
| 2 | Thomas | 35 |
| 3 | Jack | 70 |
| 4 | Selmac | 40 |
| 5 | Patrick | 80 |
We can see that if we generate a value between 0 and 240, than if it is between 0 and 15, we choose Billy, if it is between 15 and 50, we choose Thomas, etc.
Here is the code for the Select Function:
A short test Main() routine that can be used to… test it:
The test is created in such a way that the values can be thought of directly as percentages. The resulting output shows that after a run the occurences of each lie around the percentages as given; Bill appears 50 percent of the time on average, Tom 20 percent, Dick 30 percent, etc. Obviously there is no requirement that the values add up to 100, but the values end up as percentages anyway. (choosing the values 100,40, and 60 for the probability array results in similar results).
This particular method has a bit of a “problem”; what if we run it repeatedly on the same array? Then we are constantly recreating the sumulations array and calculating the totals. How can we cache it? Easy- we use a Dictionary and keep weak references to the given array.
But all is not that simple! This is a generic method and the type T could easily change between calls- so what do we do? Well, it is possible to create a static object that contains a Dictionary indexed by a Type that has a value that is a KeyValuePair<weakreference ,List<T>>, and then inspect the Dictionary for the appropriate values, make sure the cache doesn’t get to big, dispose ofthe WeakReferences that point to arrays that have since been destroyed, blah blah, tricky business. We don’t want that, because for one thing it will be a pain to write- and for another, it will probably be slower overall to begin with. Instead, how about absolving the method itself from the responsibility, and having a ref parameter that can accept a calculated sum array.
For me, the above testing Main() routine took 200ms to execute, on average (I placed calls to System.Diagnostics.Stopwatch members before and after the loop). There was no appreciable difference in speed. Thnakfully, however, the extra logic did not slow it down, either.
The speed improvement can be seen when we have a lot more members. With 5000 members in the probability and Values arrays, and executing a Select on them 50,000 times, the average time was around 5-6 seconds. When the Main function instead gave a float [] ref as the third parameter, the average time dropped to one second. The code for the revised version of the procedure. This also adds some overloads:
A lot of the above could even be implemented as Extension methods to the appropriate classes, making it seamless.
Since I am working on a game, dealing with vectors and speeds and whatnot is common. One frequent requirement is for items to move at a random angle at a random speed within a given range. The obvious base case here is creating a Vector given a angle and a magnitude:
This uses standard trigonometry to calculate what would be the X and Y axes of a fictitious triangle with the given direction as it’s hypoteneuse. Extending from this, we simply create a few extra routines that perform the randomizations:
easy as 3.1415926!
Another interesting endeavour is simplifying the otherwise messy world of Object serialization, such as easily converting a Serializable Object to and from a Stream:
[code]
public static void ObjectToStream<T>(T saveme, Stream outstream) where T : ISerializable
{
BinaryFormatter bf = getFormatter();
using(GZipStream gz = new GZipStream(outstream,CompressionMode.Compress))
{
bf.Serialize(gz, saveme);
}
}
public static T StreamToObject<t>(Stream instream) where T : ISerializable
{
BinaryFormatter bf = getFormatter();
using(GZipStream gz = new GZipStream(instream,CompressionMode.Decompress))
{
return (T)bf.Deserialize(gz);
}
}
[/code]
This also plonks in a bit of compression through the use of a GZipStream.
Anyway, that’s a quick sampling of a few snippets of possible usefulness
I see this question semi-frequently on forums. It’s a reasonable question on the surface. However, the fact is that there is no “Best language for a beginner”. Truly, the very idea that a given computer language could be “better for beginners” than another is downright assinine.
Consider human languages. A person learns language over time, and there isn’t any more difficulty for different languages; the skill develops through practice. Chinese isn’t “harder” to learn than English, for example; but it is harder to learn when you know english.
So how does this extend into computer languages?
Well, the first computer language you learn won’t matter, just as the first Human language you learned doesn’t really matter.For Human languages, the big thing you are learning is how to express yourself to others. For Programming languages, the big thing you are learning is how to express yourself- to the computer.
Once you learn one imperative programming language, the others are easier to learn; same way with human languages. Once you know one germanic language, the others are typically easier to learn.
Of course, it’s harder to learn Chinese or Japanese when you are used to a latin alphabet; for programming languages, this “barrier” is typically found between imperative, Declarative, and functional languages. of course the actual difficulty is not quite at the same level; but functional languages are fundamentally different in many ways from imperative languages, enough that trying to take what you learned via programming in an imperative language and applying it to a functional one can do more harm than good to your learning process, just as trying to apply your understanding of English will harm attempts to learn most non-germanic languages, trying to apply an understanding of Chinese/Japanese/etc to learning English will harm attempts to learn it as well.
Additionally, one issue I find is that many people will say that “language X is easy to learn because it’s like plain english”. Which is a flawed perspective, since that brings with it a lot of language baggage; english is designed for communicating between people; a programming language is designed for communicating between a person and a computer (or rather, the interpreter/compiler which makes it into something the computer understands, but let’s not cloud the issue). So you end up with a psuedo-english language that tries to be declarative but at the same time isn’t english; SQL, for example, is english-like, but I’d be hard-pressed to say that “Select * from Customers Where CX>6″ is “plain english”. It’s easy to understand, but it’s restrictive; after all, in english the same concept could be expressed as “choose all fields from the customers table where the record in question has a CX field greater than 6″. But that is far from valid SQL, which has a far more restrictive grammar and syntax. (if it didn’t, parsing it would be a nightmare).
This is how I’ve always felt about it. What is important isn’t what specific language you learn but that you learn the concepts involved; for imperative languages this would be references, functions, recursion, variable allocations,object mutability, (and for OOP languages the various OOP concepts, such as polymorphism, aggregation, composition, delegation, etc). Functional languages, (and some imperative languages that integrate functional features) it’s things like lambdas, recursive definitions,Higher-order/First-class functions (Functions that take other functions as arguments), pure functions, strict versus non-strict evaluation, catamorphism, etc.
Once you learn the concepts, you can use pretty much learn any language with minimal effort, you just need to learn the syntax.(unless you are jumping across a declarative/imperative/functional divide, in which case you also need to learn and relearn other concepts as well). Overall, however, Learning a syntax is easy; the first programming language you learn is hardest no matter which one you choose simply because you have to learn the syntax at the same time you are learning all sorts of “new” concepts. It doesn’t matter what language you choose; it will always be “harder” to learn than later languages for you.
It has been mentioned that PASCAL, a fictitious language, apparently contradicts my points here. The argument being that languages that are easier to write functionality in will be easier to learn.
However, this misses the point. The ease of learning of a first programming language is absolutely pointless, because it isn’t the syntax or structure of a given language that gives you the tools to coalesce those language elements into algorithms, and therefore solutions, but rather your understanding of base concepts. The argument for PASCAL (again, a fictitious language that doesn’t exist, evidently they truly meant Pascal) was essentially that it needed less code to read and write to the console. For example:
is more “concise” and “easier to learn” than the equivalent java code:
The argument essentially rests on the faulty premise that Writeln() is somehow “easier to learn” than java.out.println(). What such a perspective fails to take into account is the fact that Pascal and java are semantically quite different and based off of different programming models. Pascal is a structured programming language that divides it’s functions into units, but doesn’t (except in later incarnations such as Object Pascal and Delphi) support Object Oriented programming concepts.
This can be examined by merely looking at, say, the Writeln() function. It has more than one argument, and if the first of those arguments is a file handle, the output is written to that file. The requirements for creating and opening a file are less than easy- for example, a file is opened using the Rewrite() function, after you call Assign() to assign a file name to the file handle. Memorizing otherwise arbitrary function names and how they fit into a number of contexts is hardly easier to learn. Java, being Object Oriented bases it’s run-time library on Objects. the System class has a number of static fields that expose a number of System level objects; the “out” field represents the standard output stream, and is an output stream object, in fact; therefore in order to write to the standard output stream, things can be more verbose. In the case that a routine needs to repeatedly access and write to the output stream, it can easily be cached in a local variable- or really any variable at all. The point is that neither language makes it easier to learn the concepts required to implement algorithms. Java has a relatively basic implementation of Object Orientation (it is missing multiple Inheritance, proper generics, functions as objects, and metaclasses), and Pascal is a good implementation of the structured programming paradigm. Object Oriented concepts build upon structured programming concepts, and since you would have to learn the former first, one could argue that Pascal might be a better choice. However, there is still the crux of syntactic difference; additionally, being exposed to Object oriented syntax early on- even if one doesn’t understand it- could make it easier to absorb the concepts behind those peculiarities later on.
Of course, Pascal isn’t a modern language; it’s modern Equivalent, Delphi, fully supports Object Oriented Programming- even better than Java ever will, in fact- but that doesn’t mean it’s either a good or bad choice for a programming language to initially learn. I stick to my original perspective that it doesn’t really matter what language a person learns, what is far more important is they stop beating around a bush on some decision that they think is important and make it. It’s like debating over what type of cake a person should eat first to properly have the cake experience. Thing is- chocolate, spice, vanilla, fruit, etc. Whatever cake one chooses, it’s all cake and your experience is going to initially be coloured by that first cake. The only way to properly experience what a “cake” is is to have a variety of different cakes- the one you eat first is irrelevant. Same with programming languages; the only way to properly experience all the concepts and idioms involved is to learn a variety of different languages. The first one is going to always be a barrier because you have to become accustomed to the more strict grammars and syntax used with programming languages. Unlike a human language- such as english, where misspellings or grammatical ambiguities might confuse the reader or get you weird looks or a laugh here and there, with programming languages the interpreter or compiler is going to take everything you say literally and if it cannot understand what you are saying it will get very cross. Some compilers will put up with more ridiculous constructs- for example, C++ will happily compile code that makes absolutely no sense even to the most trained C++ programmer (and the result makes an equal amount of sense); others are restrictive, and will verbally assault you if you miss a single letter (Pascal, Delphi) others try to help you by doing stupid shit and inserting syntactic characters where it thinks you might need them (javascript). Anyway, my point is, such details aren’t important; the base concepts are there in all languages, just like all cakes are made with certain base ingredients and the unique flavour is added to the cake batter and supplemented (in most cases) with frosting.
As I posted previously here , Sorting a Listview can be something of a pain in the butt.
In that article, I covered some basics on providing a class that would essentially give you sorting capabilities for free, without all the messy code that would normally be required. A lot of the code required for sorting is mostly boilerplate with a few modifications for sorting various types. As a result, the generic implementation works rather well.
However, as with any class, adding features never hurts. In this case, I got to thinking- why not have right-clicking the ColumnHeaders show a menu for sorting against that Column? Seems simple enough. I quickly learned that apparent simplicity often is misattributed.
I faced several issues. The first thought was that I could hook a Mouse event for Right-Clicking a column header. Unfortunately, I soon discovered two facts about the .NET ListView control. First, was that there was no event for right-clicking a header control. Second, no even was fired at all by the ListView control when you right-clicked a header.
This left me stymied. How the heck do I implement this feature? I discovered something of a “hack” however, in that when the ListView’s ContextMenuStrip property is set, that ContextMenu Strip will be shown regardless of the location the ListView is clicked. This at least gave me something to work with. Since a ContextMenuStrip’s “Opening” event can be easily hooked, we can use that as an entry point and perform needed calculations to determine if we are indeed on a columnheader.
Which brings me to the next problem, which is determining when a columnheader was in fact the item that was clicked. This requires determining the rectangle the Header control occupies, first. The Header Control is a child control of the ListView; as such, a platform Invoke using the EnumChildWindows() API was required, something like this:
private Rectangle _HeaderRect;
private delegate bool EnumWindowsCallBack(IntPtr hwnd,IntPtr lparam);
[DllImport("user32.dll")]
private static extern int EnumChildWindows(IntPtr hwndParent,EnumWindowCallBack callbackFunction,IntPtr lParam);
[DllImport("user32.dll"]
private static extern bool GetWindowRect(IntPtr hWnd,out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private bool EnumWindowCallback(IntPtr hwnd, IntPtr lParam)
{
RECT rct;
if(!GetWindowRect(hwnd,out rct))
{
//first child of the listview should be the header control
_HeaderRect=Rectangle.Empty; //likely the listview is not in Details mode, so there is no header control.
}
else
{
_HeaderRect = new Rectangle(rct.Left,rct.Top,rct.Right-rct.Left,rct.Bottom-rct.Top);
}
return false; //cancel enumeration.
}
private static ColumnHeader [] GetOrderedHeaders(ListView lvw)
{
ColumnHeader [] returnarray = new ColumnHeader [lvw.Columns.Count] ;
foreach(ColumnHeader loopheader in lvw.Columns)
{
returnarray [loopheader.DisplayIndex] = loopheader;
}
return returnarray;
}
Quite a bit of boilerplate to add in. Basically, the idea is that we will hook the contextMenu Opening event of the Listview, (and we add a context menu to hook if the listview in fact doesn’t have one) in our constructor; and then when we receive the event we need to determine if the click occured within the area of the header control of the listview, if so, we cancel the event (which stops the default context menu from appearing) and show our own menu for the columnheader, which we can acquire using a bit of math and the static “GetOrderedHeaders” function, which retrieves the array of columnheaders of a ListView in order of appearance Left to Right (since the user could rearrange the Columns).
So First, we need to add code to the GenericListViewSorter’s Constructor. We also have a few private variables that are added; in this case, we need a ContextMenuStrip variable called “_ghostStrip” which we will use if we need to create a context menu for the control, since we don’t want that to appear in the default case. Of course we create our own ContextMenuStrip which we will show in the event instead of the default when appropriate. so we add this beneath the existing code in the constructor:
if(handleListView.ContextMenuStrip==null)
{
handleListView.ContextMenuStrip = new ContextMenuStrip();
handleListView.ContextMenuStrip.Items.Add("GHOST"); //add a ghost item so we get the Opening Event
_ghoststrip = handleListView.ContextMenuStrip;
}
//create OUR context menu
_headerContextMenuStrip = new ContextMenuStrip();
//add a ghost item to make sure Opening will fire.
_HeaderContextMenuStrip.Items.Add("ghost");
handleListView.ContextMenuStrip.Opening += ContextMenuStrip_Opening;
handleListView.ContextMenuStripChanged += handleListView_ContextMenuStripChanged;
Of course we need to add the two referenced event handlers, too. The ContextMenuStripChanged being a rather simple implementation designed to keep changes in the contextmenu of the listview from causing us to balls up and stop showing ours (since we are now hooking a orphaned context menu not being shown by the listview).
void handleListView_ContextMenuStripChanged(object sender,EventArgs e)
{
OurListView.ContextMenuStrip.Opening+=ContextMenuStrip_Opening;
}
Now the meat of the code is in the ContextMenuStrip_Opening() routine. This will need to determine wether its applicable to show the Column menu, or the already present menu (which it doesn’t show either if it happens to be the _ghoststrip). This is accomplished by use of the GetCursorPos() API routine paired with the already present GetWindowRect() implementation, which we update by calling EnumWindows.
void ContextMenuStrip_Opening(object sender,System.ComponentModel.CancelEventArgs e)
{
//first, get screen coordinates of Cursor.
POINTAPI gapi;
GetCursorPos(out gapi);
Point gotposition = new Point(gapi.X,gapi.Y);
//acquire the HeaderRect of the control...
EnumChildWindows(OurListView.Handle,new EnumWindowCallBack(EnumWindowCallback),IntPtr.Zero);
//if the mouse position is within the retrieved rectangle, cancel the display of the normal menu and create and show ours.
if(_HeaderRect.Contains(gotposition))
{
e.Cancel=true;
int xoffset = gotposition.X - _HeaderRect.Left;
ColumnHeader clickedheader = HeaderAtOffset(OurListView,xoffset);
if(clickedheader != null)
{
//create the context menu as needed.
_HeaderContextMenuStrip = new ContextMenuStrip();
_HeaderContextMenuStrip.Tag = clickedheader;
//two items, one for ascending order, one for descending order.
ToolStripMenuItem AscendingHeaderItem = new ToolStripMenuItem(String.Format("Sort Column \"{0}\" Ascending",clickedheader.Text));
ToolStripMenuItem DescendingHeaderItem = new ToolStripMenuItem(String.Format("Sort Column \"{1}\" Descending",clickedheader.Text));
//if the current sort column is the header, check it off and disable it.
if(CurrentSortColumn == clickedheader)
{
if(OurListView.Sorting ==SortOrder.Ascending)
{
AscendingHeaderItem.Checked=true;
AscendingHeaderItem.Enabled=false;
}
else if (OurListView.Sorting==SortOrder.Descending)
{
DescendingHeaderItem.Checked=true;
DescendingHeaderItem.Enabled=false;
}
}
AscendingHeaderItem.Tag = ClickedHeader;
DescendingHeaderItem.Tag = ClickedHeader;
//set event handlers for the two items.
AscendingHeaderItem.Click+= AscendingHeaderItem_Click;
DescendingHeaderItem.Click+= DescendingHeaderItem_Click;
//add them to the context menu strip.
_HeaderContextMenuStrip.Items.Add(AscendingHeaderItem);
_HeaderContextMenuStrip.Items.Add(DescendingHeaderItem);
//display the menu.
_HeaderContextMenuStrip.Show(gotposition);
}
}
else
{
//show the default menu, but only if it isn't the ghoststrip.
if(OurListView.ContextMenuStrip == _ghoststrip)
e.Cancel=true;
}
}
The events for the two buttons basically sort based on the columnheader in their tag, nothing particularly special there. the actual details can be seen in the source file itself, really.
It actually works quite well, I’m using it in a production application, and it’s working quite well.
Some obvious enhancements, of course, include making it possible to customize the shown menu, to present other options; perhaps a delegate or event that can be hooked that is given the Strip and the clicked column, and any number of other parameters? This would essentially give the equivalent of a ColumnHeaderRightClicked type event, too.
Running a website isn’t always fun or easy. And for me, it has never been profitable. But it wasn’t really about profit; it was about offering content to people interested in said content. That is, until recently.
Until recently, this site’s (admittedly very cheap and quite reliable) hosting and Domain were paid for out of pocket from earnings from my “normal” job, which was a crappy retail thing whose details are both embarassing and irrelevant. In any case, I recently quit/got fired (depends who you ask), and as a result I am trying several things.
First, I want something involving computers; or at least something that will leverage my abilities with regard to their hardware and software. I am sick and tired of jobs that are “work”; now, don’t take that the wrong way. I am willing to work, but I don’t want work that doesn’t adequately make use, and even aim to expand, my skillset. My previous job was a brainless activity, and it’s intellectual demands could probably be met by small mammals. It didn’t use any of my computer related expertise that I’ve developed over the years. they are hardly professional level abilities but they still exist and I want them to be used in a manner that I can both live off of, find enjoyable and most importantly develop those abilities further. As a result of this, I have been scouring for such locations in my area (relocation at this juncture is not a financially able decision). I have found a few, but they appear to be small shops unlikely to need additional personnel and possibly even struggling to keep out of the red as it is (and thus unlikely to risk the hiring of more employees). I have contacted a few, but none have gotten back to me, and that is rather discouraging (if not a bit unsurprising). Barring those possibilities, which I will admit feel rather far-fetched (even if my skillset would still be a superset of what is needed for those occupations), there is only one other chance. And it’s hypocritical because I ranted about it before in a post I have since hidden since I applied to these places.
Brick & Mortar electronics retailers. Now, I’ll be honest; I’ve personally not had issues with them myself; my own laptop was purchased from Future Shop, and the people there didn’t fit the stereotype often prescribed of them. They do have a bit of an aura, particularly on the support forums I visit, although I suspect there is a bit of a correlation since the only times somebody generally posts on a computer help forum would be after they have problems with the support and guidance provided by a Brick & mortar store, so in many ways we only hear the bad stories. I imagine this is not atypical; you really only hear the bad news a lot of the time.
My reasoning on this is simple. It would be better than what I was working at before. At the very least, there will be electronics involved and I can apply my actual knowledge, rather then having it go to waste aside from my personal endeavours.
Ironically, the most promising (in terms of fit) out of these that I visited was the most unexpected; London Drugs. This is obviously not primarily about computers and electronics, however they do have a relatively large electronics section, and from what I heard while there they truly do know what they are talking about; the staff I overheard knew the specification limit for USB cables I have to say that was pretty impressive, given the common stereotype behind computer retail. And it was much better than Best Buy, which was a bit sour; as one may know, all these locations generally only allow applications on-line (which if you ask me is kind of stupid); as such I was merely given a card or paper thing that had a URL on it, but that URL is dead. Which makes sense since the paper was printed in 2003. Not a good impression.
Now that said that is also a good thing because I rather enjoy the self-indulgent honour of knowing I am smarter than my colleagues, even if I don’t express that too loudly. Careful posturing could mean quick promotions, but, there is the additional problem that I think much of that is commission and if that is the case I would probably be screwed. I’m not a salesman, I can lie, but not to intentionally deceive somebody in a way that only serves to benefit me. I couldn’t in good conscience recommend say Monster Cables over more expensive cables because I have yet to see any verifiable third party data justifying that extra cost. This goes for much of the other stores that would have this as well. The only saving grace might be that much of these places have service centers where techs repair the machines; I can say with some conviction that I would be, if anything, over-qualified for such a position, given my experience dealing with hardware, software, and a multitude of Operating Systems. It might not leverage my abilities with Programming languages, but that is something I can still develop on my own; eventually and with some luck I may find a position that fits with those skills as well, but right now it’s more or less me trying to desperately claw at least one more rung up the ladder to try to leverage the unique skills that I do have, rather then sitting at the bottom of the food chain. (metaphorically speaking).
The other alternative would be to try to leverage what I already have- this website, to be precise. it’s paid for the next several months, and I have had adsense on it for a while but that’s generated a grand total of I think 20 dollars over the last two years, which isn’t close to the money I spent on the site and it’s maintenance. I also added a donation button to the main page, but nobody has used it. Maybe it’s broken. I like to think my tools and applications are useful to somebody- aside (from myself, I use BCSearch rather frequently), but it’s starting to appear that that is not the case, and it’s rather discouraging. I don’t feel their quality would fetch a price tag even if I wanted it to, given the improvements to BASeBlock, I might be able to charge a reasonable price, but as a game it’s value is much diminished because plenty of other, much higher-quality games can be found via other distribution methods. Additionally, it would counter my previous assertions that I “would never charge” for it, making me something of a hypocrite, which to be fair I don’t care about. It’s that, or other ad networks, and I’m trying them but
The fact is, I’ve spent a fair lot of time working on all these applications, and While I can’t deny or dislike the fact that there is a measurable gain in aptitudes for development with each new project, the fact that none of them gives anything else back- neither in the form of a income nor in the manner of a simple “hey, thanks for this tool”, is extremely discouraging. The market for software is simply not the same as it once was, especially for games. I have tried to offer my abilities for software development and website design for freelance work, and I am cautiously hopeful that I may be able to offer my skills to those in need of them.
The basic problem, as my title ascertains, is that it can be difficult to properly get one’s foot in the door; How do you distinguish yourself and your skills from the multitude of others who are vying for the same positions but might not be as good a fit? Especially when your only interaction with a prospective employer is by way of online communication?
As with most of my projects, progress is usually slow because it’s something I do “when I feel like it” rather then on a schedule. Because of this I often have a lot of “design-time” where I don’t actually write code but idly wonder about what I could do to make it better.
One consideration I recently decided on was supporting the packaging of the various files ā images, sounds, etc ā into a zip file. This came about as a result of my experience (easy enough) of using gzipStream to make the size of the serialized LevelSet data a tad smaller (the default levelset, which is 5 levels, still weighs in at about 145KB; most of this is because it stores a lot of PointF structures from the PathedMovingBlock that I recently added, but I won’t get into that. In any case, I considered at the same time- why not allow the loading of files from a zip?
Of course, this is hardly a new idea. I never thought it was. placing the application/game data into one monolithic (and easier managed file-system wise) file is ancient; games have been doing it for ages. In either case, since I had decided to use ZIP (rather then, say, define my own package file like I did with my Visual Basic BCFile project) I had to be able to work with zip files.
Thankfully, there are a lot of free solutions to read,extract, and otherwise deal with zip files from .NET. after some searching, I decided on dotnetzip
. The reasons I decided on it were simple: it’s easy to use, and it supports both extracting as well as creating zips. I’d rather learn one library rather then several to perform the various tasks in the future. The first step was to decide how it was all going to be done.
A little overview of how I had it arranged in the code may help. The Sounds and Images are managed by classes called cNewSoundManager and ImageManager respectively. recent changes have caused me to rewrite the SoundManager to create the “New” SoundManager, which supports different adapter classes for using various sound libraries (of which BASS.NET has become my top choice).
Thankfully, during the creation of Both ImageManager and SoundManager, I made it able to accept a number of paths in their constructors via a overload accepting an array of Strings. In fact, it was the “low-level” implementation for loading; the other overrides simply transformed their data into an array and called it, so I knew that worked. Although my ImageManager could probably be modified to load files from a stream (the ZipFile class can retrieve a inputstream for the files in a zip) the SoundManager could not feasibly do so; many sound libraries will only load from files, and since most of them are really wrappers around even lower level libraries, I couldn’t optimistically assume that I would always be able to convert a filestream into something I could use; I realized that the “Driver” classes could always take the passed in stream and create a file, but that sort of redirects the issue. Instead, I decided to leave it as-is (loading from files) and instead make it so that during the bootstrap phase (where it loads images and sounds) it also extracts the contents of any zip files that are in the application data folder as well.
I chose to change the extension I would use to bbp (Base Block Package) so that the game won’t get confused or screwed up if a standard ZIP happens to be in the same folder. The first question however is where I would extract these files too; obviously it was a temporary operation, so I opted to choose the system Temp folder, which is easily obtained in .NET via Directory.GetTempPath(). I then decided that as I enumerated each zip, they would be extracted not to this temp folder but to another folder that would be created beneath it; this way, the files in each ZIP file can have conflicting names, and still extract properly. (although at this time that will cause both ImageManager and SoundManager to throw a fit, I decided it best to not add a third class that didn’t understand that files in different folders can have different names). The next problem was easy; I simply took all the various folder names and added them to the arrays I passed to the SoundManager and ImageManager constructor. Easy as pie.
Now I needed to make sure that when the program terminated, the files were deleted. During startup it detected if the special temp folder existed and deleted it, but it would be ideal if that folder could also be deleted when the program is closed normally. the problem here is that I was initializing all of this in a static constructor (well, not really, since apparently Mono didn’t like me using static constructors for this, but it was still a static routine). There is, however, no Static “Destructor” that I could use. So I opted to create a small private class implementing IDisposable that I could create as a static variable and initialize with the name of the temporary folder to delete; the Dispose() method would then delete it, easy as pie.
However, upon testing, I encountered an error; apparently, the handle was still open in the dispose routine. After a little digging, it was clear that the problem was at least partially as a result of the Image.FromFile() method, which apparently caches that it was taken from a file as well as the filename and will keep it open as long as the image is around; since I couldn’t always be sure that the temporary class would be disposed after the ImageManager (and therefore the various Images it holds) it was difficult to make sure they were closed.
However, I decided to change my use of the FromFile() method to something that won’t pass the Image class any filename data at all; that way the Image class couldn’t possibly hold the file open, as long as I close it properly myself.
To do so, I replaced the code:
With:
And so far, it’s worked a treat.
For the user interface between a user and a computer, the basic options are mouse, and keyboard. Of course, joypads and joysticks are available and can be programmed to do all sorts of things, but such interface devices are generally used only for games.
For the seasoned Computer user, the keyboard is, IMO, far more powerful then the keyboard as far as strength of association and muscle memory is concerned. buying a new mouse that has a different shape can feel “Strange” for a while, but for me it takes maybe a few days, or a week. Buying a new keyboard with a different layout for the various “periphery” keys can take me upwards of a month.
As a user learned about the computer, eventually so too does their understanding of how various commands are done with the keyboard. When a person first learns to use a word processor, for example, they may use the Copy and Paste options on the menu, or in the toolbar. However, as they use these features more and more, they eventually discover, are told, or otherwise learn about the keyboard shortcuts for performing these tasks. In the same fashion, they will start out by selecting text, moving throughout their document, and so forth solely with the mouse. Eventually, they discover arrow keys, and later, the control block keys.
Arrow keys
The arrow keys were originally only present in the number pad area of the original IBM PC and XT keyboards. With the AT keyboard, the arrow keys were introduced and have traditionally been present beneath the control block keys, to the right of the main alphabetic keyboard block.
Today, the Arrow keys serve a myriad of functions. within any Windows edit box when it has the focus, the arrow keys can be used to move about a document. in combination with the Shift key, such movement is accompanied by the selection of the text. combined with the Control key, the selection moves a word at a time. A seasoned keyboarder will always beat out a mouser at the same text operation. The reason is mostly because, for typing, ones hands are both busy, well, typing. in order to click a button, toolbar, or menu, one needs to move their main hand (depending on their left or right handed ness) and move the mouse, and click it’s button. in contrast, one can perform the same task of most toolbar buttons using a number of keyboard shortcuts.
Control Block keys
For what I do with my computer, which involves a lot of editing of programming code, blog entries, web page files, and forum posts, the control block keys have become invaluable. The control block keys are the often ignored block of keys consisting of the Insert, Home, Page Up, Page Down, End, and Delete keys. When used properly, and in conjunction with modifier keys such as Control and Shift, one can perform a myriad of functions that take 5 or 10 seconds using the mouse. Use of these keys for selecting, copying, pasting, and moving text around has become almost second nature for me. However, this streamlined use completely disappears when I am forced to use a new keyboard whose layout differs. my current keyboard (MS Wired 500) has the control block keys in a vertically biased rectangle consisting of Home and End, Insert and Page Up, and Delete and Page down.
when I first bought the keyboard, such a layout was clunky and took a lot of work to get used to. it ruined many a programming and debugging session as my mind was taken from the task and hand and instead had to focus on retraining my muscle memory. It took nearly, if not over a month before I became as proficient as I was. Oddly enough, my laptop used a even stranger layout, whereby the control block keys were aligned down the right side of the keyboard in a single column- Home,Page up, Page down, End. Delete is positioned in a horizontal block of keys above those, containing what is often the rightmost set of function keys on the top of the keyboard, Print Screen, Pause, Insert, and Delete. due to this layout the Delete key is actually right above the home/end… etc block of keys. The laptop I use now, a Toshiba Satellite L300, has a keyboard layout very similar to it’s “ancient” predecessor whose layout I was used to, my Satellite Pro 440CDX. the 440CDX had a few “quirks” in the keyboard department, for example, the windows and application keys were moved from their normal position on the bottom row to the left and right of the spacebar, respectively, to pinky stretching positions at the upper right, where my newer model satellite has the insert and delete keys, who, on the 440 CDX, took up positions to the immediate left of the Tilde key, which was also moved to the bottom row of keys with the space bar. So the bottom row went Ctrl, Fn, Alt, Spacebar, Tilde/backtick, Insert,Delete left, down, right. this made any attempt to use the right alt key (which, admittedly, is usually rather neglected on the average keyboard anyway) actually press the tilde/grave key. However, and perhaps more important, attempts to press tilde (which, having to type the short file name for long file names comes up more often then some people might expect) will type escape. Which could do any number of things.
Anyway, my point is, it was completely different from the normal keyboard I was using for my desktop. And yet I was equally fluent with it, as it became my main development machine for quite some time (I’m referring to the 440CDX). Therefore the main cause for such familiarity isn’t really a set number of “memorized” layouts, but rather frequency of use. To test, I started up my old laptop. I noticed several interesting changes keyboard wise. for some reason, I had difficulty typing keys in the upper left. my fingers would try to strike a key that they/I thought was there, only to meet the spot between two keys or pressing hte wrong key altogether. Additionally, and not strictly related to the keyboard, I found myself having the exact opposite problem I did when I first went to adjust to the newer laptop; mouse movement.
The older laptop used the TrackPoint II, or licensed clone, which is a small stick sticking out between the g and h keys on the keyboard. it’s nearly stationary and detects angular movement on the stick and converts it to mouse movement on-screen. the newer technology that has become the norm for laptops is the touchpad. I cursed loudly when trying to use this at first, often trying to use the trackpoint instinctively to move to mouse, only to meet with nothing, then remembering the touchpad, cursing again, etc.. basically, it took some getting used to.
However, now, whenever I fire up the old 440CDX to make sure it hasn’t died, I find myself trying to move the mouse cursor with a non-existent touchpoint. The exact opposite issue I had when first adopting it.
That being said, the first conclusion one might reach is that learning the touchpad “pushed” the trackpoint II out of my mind. However, I believe this is purely a case of how much I use it; if I used them both equally, I’d probably always know exactly which one to use based on some other number of unknown mental stimuli that tell me which one it is, much as I know automatically wether to use the Desktop control keys or the laptop control keys based when I’m using one or the other. It’s rather a case of how often I haven’t used the trackpoint that has caused it to become a “second attempt” sort of interface.
Function keys
Another important and often described as “advanced” group of keys are the Function keys present on the top row of most keyboards. It was these keys that made my wireless keyboard completely unusable to me. Each block of keys is traditionally separated into groups of four. For some reason, the designers of my wireless keyboard decided to do so in groups of three. This completely screws up every single thing I do with any key other then F1,F2, and F3. For example, Pressing Control-F9 “naturally” (via “muscle memory” on that keyboard makes me press F7- the first key on the third set of keys. I would need to literally retrain my brain to use that keyboard as well, and I’d rather not go through the angst I did previously, especially not for a very specific layout which probably will not become standard even among MS keyboards.
I have been using Visual Basic 6 for many years; I have come to the point where using it is effortless; nearly any problem I have I can design and program with Visual Basic 6.
However. Visual Basic six is over 10 years old. Mainstream support ended a few years ago, and after Vista Microsoft makes no promises that programs designed with Visual Basic 6 will work. Even creating programs that support the various UI features of XP could be a chore. With Vista, Not only does one need to include the proper manifest resource or fileĀ to force their VB6 applications to link with the newer version of comctl32, but it is almost always necessary to include an additional set of directives in the manifest to make the program request administrator permissions. I have yet to determine why some of my less trivial programs crash before they even start when run with the same security as the user, but I imagine it’s directly related to COM components, their usage, and the permissions surrounding them.
Another area of concern is with the use of proper icons; Visual Basic complains when you try to use a icon with a alpha channel. However, through a few API techniques and some resource editor trickery, it’s possible to have your application use 32-bit icons both as the program file icon as well as the icon for your forms. Rather then repeat the material here, I will point you in the right direction if this type of this piques your interest. www.vbaccelerator.com- I cannot praise that site and it’s creator enough. While many of the projects and controls he has on-line I have personally attempted before finding the site (I had a somewhat working toolbar control and a control I called “menuctl” that allowed moving the main menu around as a toolbar), the sheer number of completed, documented, and well written controls on his site is simply mind-blowing. There is also a .NET section to his site as well, which brings me to my next point.
There are only a few reasons why a programmer would choose to use Visual Basic 6 for a new project today. The main reason is simply because we are stubborn, for the most part. The fact that .NET is better in many ways then VB6 does not sway us to use it. The fact is, we all feel “betrayed” in a way, but the shift to .NET. Millions of lines of code that were dutifully compatible through all 6 versions of Visual Basic 6 now break when loaded in VB.NET. But I believe, that the majority of VB6 programmers have simply been blinded to the number of problems Microsoft would have faced to continue using the same COM oriented framework that VB4 and higher have used.
COM,or, Component Object Model,(sometimes referred to as “Common Object Model” which is dead-wrong) is a Binary compatible method of providing interoperability between applications. COM was essentially designed to prevent what was known as “DLL hell”, since at that point in time DLLs provided their functionality through exposed functions, some versions not compatible with previous versions, meaning it might be necessary to, for example, have 5 different versions of MFC41.dll on ones PC. The idea was, each version of a COM component would be Binary compatible with the previous version, which means, for example, that a program designed for version 1 of “foocomponent” could still run and use version 4, but without the new features of version 4. This functionality was implemented by the creation of Interfaces. Each version of a component would add a new interface- for example, IFooComponent, IFooComponent2,IFooComponent3, etc, and client applications who want to use FooComponent would use the interface appropriate to the version they wish to use.
There was, however, one problem. Most of the maintenance between versions was left to the programmer of the component- they had to create the new interface, make sure previous interfaces worked, that old clients could still instantiate their objects, etc. Basically, it made the critical mistake of putting the user of the technology (in this case, the programmer) in a critical position and with a number of responsibilities to get things to work properly.
Microsoft, of all companies, should know that putting the programmer in a position of such responsibility is prone to failure; hell, many of them can’t even be bothered to follow standard API documentation; for example, actually reading the documentation; this resulted in hundreds of man-hours of programmer time being consumed by the creation of “compatibility shims” to let these programs work. (otherwise, installing a new windows OS would break these programs; they worked before, so as far as the user sees the new Operating System is to blame). Anyway- this failed miserably. Programmers would sometimes simply change their interfaces rather then implement new and old ones, meaning, like with the DLLs of before, new DLL versions were incompatible with the old ones.
It was clear that COM, or, at least, COM as it was presently designed, was far to dependent on the programmer to “do the right thing” then was reasonable. So, Microsoft, at some point, decided they needed a new object framework architecture.
VB6, as a COM-based language, would have required extensive changes to support this new architecture. the prospect of such a huge revision probably made them take a second glance at the language itself, and the cruft it still has from previous iterations of the basic language. aside from retaining such archaic constructs as the “GoSub…Return”, VB6 also “failed” in a sense on a number of other areas. Error-Handling, for example, was still done using “On Error” statements, which redirected flow to another segment of code. It was up to that block of code to evaluated the error, using the “Err” object (In VB1-3 there was only Err which was the error number and Error$ , which was the description), and then either resuming that same statement that caused the error ( Resume ) skipping that line, and continuing with the next, (Resume Next) or even raising the error again, causing the error to cascade up through the call stack.
This Error architecture had a critical flaw- by using this form of error handling, flow could change to the error block for any reason, at any time. This meant that if the procedure dealt with resources, such as file handles or memory blocks, it would have to keep track of what needs to be undone so that the error code could also double as partial cleanup code. Another critical flaw was simply that it was ugly; it looked and functioned nothing like the Try…Catch statements in many other languages. Also, it could become impossible to trace exactly where an error occured when errors cascaded; and error handler might be forced to handle an error from three levels down in the call-stack, so even if it understood the error in the context of the procedure, the context that the original error occured in and exactly what it means was lost.
My main language is Visual Basic 6, but I am not so blind as to reject VB.NET, or .NET as a whole, merely because it essentially replaced VB6. The truth is- we, as VB programmers, have made a large number of requests to the VB developers. VB .NET answered and fixed a huge number of those requests, and yet it is still shunned; it is clear to me that it is not merely the loss of backwards compatibility that causes such antagonism with VB6 programmers, but also the human element of resistance to change.
With previous versions of Visual Basic, one could migrate all their code to the new version with little or no difficulty.
This, however, had a price- since the new version made few, if any, requirements for conversion, old antique code would often be upgraded and imported into the new environment. Since backwards compatibility was the rule, old elements such as line numbers gotos, and gosubs remained in the language. Antiquated concepts such as type declaration characters remained in the language. Such visages of a forgotten era had no place in a modern language.
All the above being said, VB6 is still a language capable of creating modern applications; however it is important for the programmers who still use it to realize that they aren’t using it because it is superior or because .NET or any other language “sucks” by comparison, but rather as a result of their own stubborness and unwillingness to learn new programming concepts.
A anecdote, if I may, can be found in my introduction to the use of “class modules” within Visual Basic. at first, I had no idea what they were- I simply shied away from them, and stuck to Forms and code modules. I used all sorts of excuses- Class modules are slower, they bloat the code, etc. All of which were, almost universally fabricated or found on the web written by grade 8 students who barely understood the meaning of the word “class” in the context of programming or objects.
After, however, creating ActiveX Controls using the “userControl” Object, I realized the similarities, and the possibilities that could arise. My first conversion attempt was on my Current “flagship” program, the game I called “Poing”. At that time, the entire game was designed using User defined types as functions that operated on them. I understood the concept of encapsulation and managed to convert the entire architecture to a Class based object heirarchy- and it worked. My concepts still contained flaws, such as including critical game logic in down-level objects, but for the most part my udnerstanding was sound.
As my understanding of the concepts involved improved, so too did my antagonism disappear. It was clear to me that the fact that I didn’t understand classes at the time lent itself to a distaste for them- basically, the old adage that one is “afraid” of what one doesn’t understand was at least partly true. This, I feel, is at the very core of the antagonism against .NET. the main detractors of the framework are often people that neither understand the concepts involved nor do they realize how said concepts add increased possiblities and easier maintenance.
Even so- .NET has, in my opinion, one critical flaw. the IDE is slow. even on my quad core machine I see huge delays as intellisense is populated or any number of other operations. Perhaps it is a result of a mere 7200RPM hard drive? I don’t know. perhaps I need more then my current 8GB of RAM? who knows. I think, that using a 10 year old program and expecting and recieving quick responses from it have perhaps jaded me in terms of what the extra features of the new IDE actually cost in terms of performance; the delays feel like minutes, but in general it is only a few seconds. On the other hand- a few seconds is a lot longer then necessary to make one lose their train of thought. At the same time, this same argument was used against the initial usage of Intellisense; and there is no denying that although the initial display of a number of said intellisense lists can take some time, subsequent usage is nearly instantaneous, and the lists provide far more in terms of function information then the VB6 OR C++ 6 IDE could provide; this, in addition to the ease of use of assemblies between multiple .NET languages is not something that should be passed up because of an ego-centric desire to prevent change. The IT industry changes constantly. The fact that VB6 is now a “past item” should not dissuade us from moving forward because of a snobbish desire or fictitious affection for the corridor of our programming efforts for many years; the complaints about VB6 when it was introduced were very vocal. This is, no different with VB.NET, however the very complaints made about VB6 that have been remedied with .NET are now being passed off as inconsequential (since in many cases programmers have devised ways of working around limitations or even forcing behaviour that VB6 was not designed for, such as, for example the creation of Command-line programs.
The mistake Microsoft made was not the creation of .NET, but rather the belief that any sane person would move to a new platform if it was superior. They forgot the take account of the psychological factors involved.

Categories
Tag Cloud
Blog RSS
Comments RSS
Last 50 Posts
Back
Back
Void « Default
Life
Earth
Wind
Water
Fire
Light 