home comics writing pictures archive about

2017-05-08 - Parts of Speech: Verbs

Last time I said we were going to look at pronouns next, but I've decided it's better to look at verbs first. Verbs usually have a subject which is a noun identifying what is doing the verb. Verbs can also have an object which is a noun identifying what the verb is being done against. The subject/object difference has the most impact on pronouns which is why I wanted to mention verbs first.

Verbs are action words. They describe what something is doing. Words like "walk", "think", and "imagine" are verbs. Verbs are one of the most complicated parts of speech and they can have many forms. because of this the inflections of a verb are special and called conjugations.

Verb forms are constructed from several principal parts. The infinitive is the base form of a verb. The past participle is formed by adding -ed to the base form and the present participle is formed by adding -ing to the base form. A gerund is the form of a verb when used as a noun and usually matches the infinitive.

Verbs are mainly conjugated to indicate the time period over which the action is occurring. Tense describes the point in time at which the action is happening. Past tense means an action occurred in the past, present tense means an action is occurring in the present and future tense means it is occurring in the future.

Aspect is used to indicate when the action started and ended. Simple aspect indicates an action occurring regularly in the time frame indicated by its tense. Perfect aspect indicates an action starting before the time frame indicated by its tense but completed by that time. Progressive aspect indicates an action started before and continuing after the time frame indicated by its tense. Perfect Progressive aspect indicates an action started before but ending at the time frame indicated by its tense. Aspects can be thought of as modifications of tenses and so the term tense is sometimes used to refer to a specific combination of tense and aspect. The following list shows tenses and examples.

Tense Example Part Description
Simple Past I walked Past Participle An action occurred in the past
Past Perfect I had walked Past Participle An action occurred and ended before a specific  point in the past
Past Progressive I was walking Present Participle An action was occurring at a specific point in the past
Past Perfect Progressive I had been walking Present Participle An action was occurring and had just stopped at a specific point  in the past
Simple Present I walk Infinitive An action occurs in the present
Present Perfect I have walked Past Participle An action occurred and ended before the present
Present Progressive I am walking Present Participle An action is occurring in the present
Present Perfect Progressive I have been walking Present Participle An action was occurring and had just stopped before the present
Simple Future I will walk Infinitive An action will occur in the future
Future Perfect I will have walked Past Participle An action occurred in the future and ended before a specific point in the future
Future Progressive I will be walking Present Participle An action will be occurring at a specific point in the future
Future Perfect Progressive I will have been walking Present Participle An action will have been occurring and will have stopped just before a specific point in the future

Note that not all verbs follow the rules. Irregular verbs are those which have unusual participles or tense forms. Tenses themselves are also used in a variety of ways which makes it difficult to give them exact definitions. We may talk more about verbs at a later date since they are one of the most complicated parts of language.

Next time we will talk about pronouns, for real this time.

2017-03-18 - In IL: Prize Calculator (switch-2)

Last time we looked at a switch statement in C# which was implemented in IL by the switch instruction. The IL switch instruction is a lot more restrictive than the C# switch statement, for example the instruction expects its options to be continuous and only supports integers. The statement on the other hand can have large gaps between its options and also supports strings. So what happens when we have a switch statement that can't easily be implemented using the instruction?

The following program determines a user's prize based on a number. Only specific numbers get prizes and there's large gaps between winning numbers.

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace csSwitch2
{
class Program
{
static void Main(string[] args)
{
int position = 266;
switch (position)
{
case 45:
Console.WriteLine("You win a car");
break;
case 102:
Console.WriteLine("You win a TV");
break;
case 513:
Console.WriteLine("You win a cheeseburger");
break;
case 668:
Console.WriteLine("You win a hat");
break;
case 998:
Console.WriteLine("You win a potted plant");
break;
case 1054:
Console.WriteLine("You win a house");
break;
case 2045:
Console.WriteLine("You win a carrot");
break;
case 2102:
Console.WriteLine("You win a teddy bear");
break;
case 2513:
Console.WriteLine("You win a double cheeseburger");
break;
case 2668:
Console.WriteLine("You win a toque");
break;
case 2998:
Console.WriteLine("You win a pot of gold");
break;
case 3054:
Console.WriteLine("You win a mouse");
break;
default:
Console.WriteLine("You win nothing");
break;
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

Their are 12 options with a range of 3009. That would require the switch instruction to have an array with 3009 addresses where 2997 of them point to the default case. Let's see what the compiler generates for us.

Main
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 283 (0x11b)
.maxstack 2
.locals init ([0] int32 position)
IL_0000: ldc.i4 0x10a
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldc.i4 0x41e
IL_000c: bgt.s IL_004a
IL_000e: ldloc.0
IL_000f: ldc.i4 0x201
IL_0014: bgt.s IL_002d
IL_0016: ldloc.0
IL_0017: ldc.i4.s 45
IL_0019: beq.s IL_008c
IL_001b: ldloc.0
IL_001c: ldc.i4.s 102
IL_001e: beq.s IL_0097
IL_0020: ldloc.0
IL_0021: ldc.i4 0x201
IL_0026: beq.s IL_00a2
IL_0028: br IL_0110
IL_002d: ldloc.0
IL_002e: ldc.i4 0x29c
IL_0033: beq.s IL_00ad
IL_0035: ldloc.0
IL_0036: ldc.i4 0x3e6
IL_003b: beq.s IL_00b8
IL_003d: ldloc.0
IL_003e: ldc.i4 0x41e
IL_0043: beq.s IL_00c3
IL_0045: br IL_0110
IL_004a: ldloc.0
IL_004b: ldc.i4 0x9d1
IL_0050: bgt.s IL_006f
IL_0052: ldloc.0
IL_0053: ldc.i4 0x7fd
IL_0058: beq.s IL_00ce
IL_005a: ldloc.0
IL_005b: ldc.i4 0x836
IL_0060: beq.s IL_00d9
IL_0062: ldloc.0
IL_0063: ldc.i4 0x9d1
IL_0068: beq.s IL_00e4
IL_006a: br IL_0110
IL_006f: ldloc.0
IL_0070: ldc.i4 0xa6c
IL_0075: beq.s IL_00ef
IL_0077: ldloc.0
IL_0078: ldc.i4 0xbb6
IL_007d: beq.s IL_00fa
IL_007f: ldloc.0
IL_0080: ldc.i4 0xbee
IL_0085: beq.s IL_0105
IL_0087: br IL_0110
IL_008c: ldstr "You win a car"
IL_0091: call void [mscorlib]System.Console::WriteLine(string)
IL_0096: ret
IL_0097: ldstr "You win a TV"
IL_009c: call void [mscorlib]System.Console::WriteLine(string)
IL_00a1: ret
IL_00a2: ldstr "You win a cheeseburger"
IL_00a7: call void [mscorlib]System.Console::WriteLine(string)
IL_00ac: ret
IL_00ad: ldstr "You win a hat"
IL_00b2: call void [mscorlib]System.Console::WriteLine(string)
IL_00b7: ret
IL_00b8: ldstr "You win a potted plant"
IL_00bd: call void [mscorlib]System.Console::WriteLine(string)
IL_00c2: ret
IL_00c3: ldstr "You win a house"
IL_00c8: call void [mscorlib]System.Console::WriteLine(string)
IL_00cd: ret
IL_00ce: ldstr "You win a carrot"
IL_00d3: call void [mscorlib]System.Console::WriteLine(string)
IL_00d8: ret
IL_00d9: ldstr "You win a teddy bear"
IL_00de: call void [mscorlib]System.Console::WriteLine(string)
IL_00e3: ret
IL_00e4: ldstr "You win a double cheeseburger"
IL_00e9: call void [mscorlib]System.Console::WriteLine(string)
IL_00ee: ret
IL_00ef: ldstr "You win a toque"
IL_00f4: call void [mscorlib]System.Console::WriteLine(string)
IL_00f9: ret
IL_00fa: ldstr "You win a pot of gold"
IL_00ff: call void [mscorlib]System.Console::WriteLine(string)
IL_0104: ret
IL_0105: ldstr "You win a mouse"
IL_010a: call void [mscorlib]System.Console::WriteLine(string)
IL_010f: ret
IL_0110: ldstr "You win nothing"
IL_0115: call void [mscorlib]System.Console::WriteLine(string)
IL_011a: ret
} // end of method Program::Main
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

The compiler generated a ton of branching statements but no switch instructions. So what are those branching instructions doing? Let's map them out.

It starts by branching if the number is greater than 1054. This is the middle option of our switch statement. If it is greater than 1054 it then branches if the value is greater than 2513, else it continues on and branches if the value is greater than 513. 2513 is the middle option of the block greater than 1054 and 513 is the middle option of the block less than or equal to 1054. You may recognize this process of repeatedly dividing the options in half and checking if the value is greater than or less than the half way value as binary search. Instead of checking every value it checks ranges and focuses in on the value. It only checks for equality when it gets down to a few remaining options. This way it only takes 5 comparisons to get to the largest value of 3054 instead of 12. Now let's go a step further and see what happens if we use strings instead of integers.

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace csSwitch3
{
class Program
{
static void Main(string[] args)
{
string position = "266";
switch (position)
{
case "45":
Console.WriteLine("You win a car");
break;
case "102":
Console.WriteLine("You win a TV");
break;
case "513":
Console.WriteLine("You win a cheeseburger");
break;
case "668":
Console.WriteLine("You win a hat");
break;
case "998":
Console.WriteLine("You win a potted plant");
break;
case "1054":
Console.WriteLine("You win a house");
break;
case "2045":
Console.WriteLine("You win a carrot");
break;
case "2102":
Console.WriteLine("You win a teddy bear");
break;
case "2513":
Console.WriteLine("You win a double cheeseburger");
break;
case "2668":
Console.WriteLine("You win a toque");
break;
case "2998":
Console.WriteLine("You win a pot of gold");
break;
case "3054":
Console.WriteLine("You win a mouse");
break;
default:
Console.WriteLine("You win nothing");
break;
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

As you can see this program is similar to the first except it uses a string variable and string case statements. Let's see what it compiles into.

Main
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 569 (0x239)
.maxstack 2
.locals init ([0] string position,
[1] uint32 V_1)
IL_0000: ldstr "266"
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: call uint32 '<PrivateImplementationDetails>'::ComputeStringHash(string)
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: ldc.i4 0x710e415f
IL_0013: bgt.un.s IL_0066
IL_0015: ldloc.1
IL_0016: ldc.i4 0x4981fbad
IL_001b: bgt.un.s IL_0043
IL_001d: ldloc.1
IL_001e: ldc.i4 0x2e9ae600
IL_0023: beq IL_00db
IL_0028: ldloc.1
IL_0029: ldc.i4 0x3d24bbac
IL_002e: beq IL_012f
IL_0033: ldloc.1
IL_0034: ldc.i4 0x4981fbad
IL_0039: beq IL_0183
IL_003e: br IL_022e
IL_0043: ldloc.1
IL_0044: ldc.i4 0x55973d92
IL_0049: beq IL_0144
IL_004e: ldloc.1
IL_004f: ldc.i4 0x6933d7c2
IL_0054: beq.s IL_00c6
IL_0056: ldloc.1
IL_0057: ldc.i4 0x710e415f
IL_005c: beq IL_016e
IL_0061: br IL_022e
IL_0066: ldloc.1
IL_0067: ldc.i4 0x94902f75
IL_006c: bgt.un.s IL_008e
IL_006e: ldloc.1
IL_006f: ldc.i4 0x84aadb8f
IL_0074: beq.s IL_00f0
IL_0076: ldloc.1
IL_0077: ldc.i4 0x8ce38d62
IL_007c: beq.s IL_00b1
IL_007e: ldloc.1
IL_007f: ldc.i4 0x94902f75
IL_0084: beq IL_011a
IL_0089: br IL_022e
IL_008e: ldloc.1
IL_008f: ldc.i4 0x9aff1550
IL_0094: beq IL_0159
IL_0099: ldloc.1
IL_009a: ldc.i4 0xb0d0fd37
IL_009f: beq IL_0198
IL_00a4: ldloc.1
IL_00a5: ldc.i4 0xdbe097dd
IL_00aa: beq.s IL_0105
IL_00ac: br IL_022e
IL_00b1: ldloc.0
IL_00b2: ldstr "45"
IL_00b7: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_00bc: brtrue IL_01aa
IL_00c1: br IL_022e
IL_00c6: ldloc.0
IL_00c7: ldstr "102"
IL_00cc: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_00d1: brtrue IL_01b5
IL_00d6: br IL_022e
IL_00db: ldloc.0
IL_00dc: ldstr "513"
IL_00e1: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_00e6: brtrue IL_01c0
IL_00eb: br IL_022e
IL_00f0: ldloc.0
IL_00f1: ldstr "668"
IL_00f6: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_00fb: brtrue IL_01cb
IL_0100: br IL_022e
IL_0105: ldloc.0
IL_0106: ldstr "998"
IL_010b: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0110: brtrue IL_01d6
IL_0115: br IL_022e
IL_011a: ldloc.0
IL_011b: ldstr "1054"
IL_0120: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0125: brtrue IL_01e1
IL_012a: br IL_022e
IL_012f: ldloc.0
IL_0130: ldstr "2045"
IL_0135: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_013a: brtrue IL_01ec
IL_013f: br IL_022e
IL_0144: ldloc.0
IL_0145: ldstr "2102"
IL_014a: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_014f: brtrue IL_01f7
IL_0154: br IL_022e
IL_0159: ldloc.0
IL_015a: ldstr "2513"
IL_015f: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0164: brtrue IL_0202
IL_0169: br IL_022e
IL_016e: ldloc.0
IL_016f: ldstr "2668"
IL_0174: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0179: brtrue IL_020d
IL_017e: br IL_022e
IL_0183: ldloc.0
IL_0184: ldstr "2998"
IL_0189: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_018e: brtrue IL_0218
IL_0193: br IL_022e
IL_0198: ldloc.0
IL_0199: ldstr "3054"
IL_019e: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_01a3: brtrue.s IL_0223
IL_01a5: br IL_022e
IL_01aa: ldstr "You win a car"
IL_01af: call void [mscorlib]System.Console::WriteLine(string)
IL_01b4: ret
IL_01b5: ldstr "You win a TV"
IL_01ba: call void [mscorlib]System.Console::WriteLine(string)
IL_01bf: ret
IL_01c0: ldstr "You win a cheeseburger"
IL_01c5: call void [mscorlib]System.Console::WriteLine(string)
IL_01ca: ret
IL_01cb: ldstr "You win a hat"
IL_01d0: call void [mscorlib]System.Console::WriteLine(string)
IL_01d5: ret
IL_01d6: ldstr "You win a potted plant"
IL_01db: call void [mscorlib]System.Console::WriteLine(string)
IL_01e0: ret
IL_01e1: ldstr "You win a house"
IL_01e6: call void [mscorlib]System.Console::WriteLine(string)
IL_01eb: ret
IL_01ec: ldstr "You win a carrot"
IL_01f1: call void [mscorlib]System.Console::WriteLine(string)
IL_01f6: ret
IL_01f7: ldstr "You win a teddy bear"
IL_01fc: call void [mscorlib]System.Console::WriteLine(string)
IL_0201: ret
IL_0202: ldstr "You win a double cheeseburger"
IL_0207: call void [mscorlib]System.Console::WriteLine(string)
IL_020c: ret
IL_020d: ldstr "You win a toque"
IL_0212: call void [mscorlib]System.Console::WriteLine(string)
IL_0217: ret
IL_0218: ldstr "You win a pot of gold"
IL_021d: call void [mscorlib]System.Console::WriteLine(string)
IL_0222: ret
IL_0223: ldstr "You win a mouse"
IL_0228: call void [mscorlib]System.Console::WriteLine(string)
IL_022d: ret
IL_022e: ldstr "You win nothing"
IL_0233: call void [mscorlib]System.Console::WriteLine(string)
IL_0238: ret
} // end of method Program::Main
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285

That's follows the same basic flows as the integer case but with a few differences. Firstly on line 68 the compiler used an internal function to generate a hash value for the string which is a unsigned integer and then it compares the computed hash against the pre-computed hashes for the string cases. Secondly instead of branching directly to the print statements it branches to a call to the string's equality function. This is to ensure that string actually matches the desired value and doesn't just have the same hash value.

Next time we will look at the Visual Basic .NET Select statement and see how it handles even more complicated cases.

2017-02-26 - Computer Engineering is Weird

Computer engineering is weird compared to other engineering disciplines. Engineers mainly work on the design part of a project. They come up with specifications that get approved by the client and then sealed by the engineer to indicate that they are ready to be used. Then the plans are given to other people who construct the project under the supervision of the engineer. In computer engineering there is rarely a separate build time or a complete specification. This is largely because programming is both harder and easier than other disciplines.

Building a program is a fair bit easier than building other things. Maybe not in terms of complexity but at least in terms of resources and personnel. You need carpenters, electricians, plumbers, painters and many other trades people  along with wood, wiring, piping, and heavy equipment to build a house. In contrast you just need programmers and computers to build a program. Programming teams also tend to be a lot smaller compared to construction crews.

On the other hand designing a program can be quite complicated. There tends to be a large number of distinct parts of a program which can interact with each other in a variety of ways. These parts can also be created and destroyed many times throughout the life-cycle of the application. Modeling these details in a simple way can be almost impossible. There's also the problem that the design and implementation of a program can be very similar. A specification is a set of instructions that describes how something should be built but a program is also a set of instructions. So it becomes difficult to write a specification that is detailed enough to be useful but not too detailed that it's basically the program written in another language.

Because of the ease of building a program and the comparable difficulty of designing teams will often skip the formal specification in favour of just building the program and the program becomes its own specification. Since the main focus is on building the project there's no need for a separate design group or a formal approval processes. Specifications are going to be created and used by the same people and change as the program is developed and details get fleshed out.

Now likely computer engineering would benefit from having more formal specification and approval processes but it requires tools specificity designed to make it practical to do so.

2017-02-04 - Parts of Speech: Nouns

We are going to start our investigation of the parts of speech with nouns. Nouns are said to name things. They are used to refer to entities, things, ideas, people, or places. Nouns can have multiple forms on inflections depending on how they are being used. These inflections are important to us because they can change the spelling of the word and can impact the spelling and word choice of the words used in association with the noun.

Proper nouns refer to specific entities while common nouns refer to general things. Proper nouns are capitalized while common nouns are not. For Example "General Petre Dumitrescu" is capitalized because it refers to a specific person while "an admiral" isn't because it refers to an non-specific person. Although these technically aren't inflections I am including them because they do change the word.

One of the main ways nouns are inflected is to show number. You can have singular nouns such as "An Apple" and plural nouns such as "Apples". In English plurals are commonly formed from singular nouns by adding s or es but some words have irregular plurals such as "Children". Uncountable nouns refer to things which can't be referred to in the singular such as "Apple Juice". You can't take a single bit of apple juice out of a glass. This often depends on how the word is being used for example you can ask for "an apple juice" or "five apple juices" in which case you mean a glass or glasses of apple juice.

Another way nouns are inflected is to show possession. For example "the cat's" or "the building's". Possession is usually expressed using an 's and sometimes just an ' if the noun ends in s. Possession doesn't necessarily express ownership.

Although not common in English some languages also inflect nouns for gender. For example "chat" is French for a male cat while "chatte" is French for a female cat. In these languages most nouns have a gender but not all of them can be inflected to express a different gender. For example "livre" is French for book and is a masculine noun but there is no feminine form of book.

Next time we will look at a subclass of nouns called pronouns.