home comics writing pictures archive about

2020-01-13 - Tomatoes

Someone recently asked me what kind of fruit I would be if I was a fruit and my automatic response was "Tomato" because that's always my response to questions about fruit. They were making a joke about bad pseudo-philosophical interview questions that are somehow supposed to provide insight about the perspective hire but I think the answer actually works for me.

The reason "Tomato" is my default response to questions about fruit is because a lot of people don't think of them as fruits.  The botanical definition of fruit is at odds with the culinary definition when it comes to tomatoes which sets up an interesting contradiction. I also find it interesting that most berries aren't berries and peanuts are closer to peas than nuts.

The other reason I replied with Tomatoes is because I actually like tomatoes. They taste good and can be used in a variety of ways. You can put tomatoes on sandwiches, tomato sauce is the basis for many pizzas and pastas. They are also used to make ketchup which can be put on anything from fries to liver.

So on the one hand tomatoes are a good fruit to represent me because I am a contrarian at heart. People say left and I think "What about right?". People say vegetable and that tomato goes "What about fruit?". I also try to be generally practical. I never want to be the person who goes "Nah, I can't do that" instead I want to be the person that goes "Yeah sure, I'll try that".

So if I was a fruit I would be a tomato, delicious and contentious.

2020-01-04 - Parts of Speech: Adverbs

Adverb is a catch all term for words that modify things that aren't nouns. They can be applied to verbs, adjectives, other adverbs, clauses and sentences. Like adjectives they serve to provide more specific context and more detail. Instead of saying "He walked away" you could say "He quickly walked away" or "She slowly walked away". Most but not all adverbs end in -ly. Some adverbs have a long form with -ly and a short for without it.

Adverbs have several classifications. Relative adverbs are used to combine parts of sentences to provide clarification. Interrogative adverbs are used in questions. Conjunctive adverbs serve to connect sentences.

Like adjectives, adverbs can also be used for comparisons. For short adverbs not ending in -ly the comparative form is created by adding -er and the superlative form is created by adding -ed. The comparative can also be created by adding more/less and the superlative can also be created by adding most/least.

Next time we will look at verbals which are words derived from verbs but used for other purposes.

2019-11-02 - In IL: Other Instructions

We've talked about a bunch of instructions so far but there were some simple ones that were either skipped or missed. I want to take the time now to go through those instructions.

ldloca (LoaD LOCal variable Address)

Push the address of a local variable onto the stack.

Instruction Description Binary Format
ldcloca.s <index> Loads the address of local variable with “short” index <index> onto the stack 0x12 <uint8>
ldcloca <index> Loads the address of local variable with index <index> onto the stack 0xFE 0x0D <uint16>

dup (Duplicate), pop

Both these instructions are used to modify the stack

Instruction Description Binary Format
dup Duplicates the value at the top of the stack 0x25
pop Removes the value at the top of the stack 0x26

add (ADDition), sub (SUBtraction), mul (MULtiplication), div (DIVision), rem (REMainder)

Pops two values off of the stack and pushes the result of the specified action onto the stack.

Instruction Description Binary Format
div.un Divides the second value popped off of the stack by the first value popped off of the stack and pushes the result onto the stack. Both values are taken as unsigned integers 0x5C
rem Divides the second value popped off of the stack by the first value popped off of the stack and pushes the remainder onto the stack. 0x5D
rem.un Divides the second value popped off of the stack by the first value popped off of the stack and pushes the remainder onto the stack. Both values are taken as unsigned integers 0x5E
add.ovf Adds the first value popped off of the stack to the second value popped off of the stack and pushes the result onto the stack. Throws exception if overflow occurs. 0xD6
add.ovf.un Adds the first value popped off of the stack to the second value popped off of the stack and pushes the result onto the stack. Both values are taken as unsigned integers and throws exception if overflow occurs. 0xD7
mul.ovf

Multiplies the second value popped off of the stack by the first value popped off of the stack and pushes the result onto the stack. Throws exception if overflow occurs.

0xD8
mul.ovf.un

Multiplies the second value popped off of the stack by the first value popped off of the stack and pushes the result onto the stack. Both values are taken as unsigned integers and throws exception if overflow occurs.

0xD9
sub.ovf Subtracts the first value popped off of the stack from the second value popped off of the stack and pushes the result onto the stack. Throws exception if overflow occurs. 0xDA
sub.ovf.un Subtracts the first value popped off of the stack from the second value popped off of the stack and pushes the result onto the stack. Both values are taken as unsigned integers and throws exception if overflow occurs. 0xDB

shl (SHift Left), shr (SHift Right)

Pops two values off of the stack and shifts the second binary value popped off of the stack a number of times determined by the first value popped off of the stack pushing the result onto the stack.

Instruction Description Binary Format
shl Shifts the value to the left, adding 0s to the right 0x62
shr Shifts the value to the right, adding duplicates of the sign bit to the left 0x63
shr.un Shifts the value to the right, adding 0s to the left. 0x64

neg (negate)

Pops a value off of the stack and pushes the negative of that value onto the stack.

Instruction Description Binary Format
neg Negates the value 0x65

conv (CONVersion)

Pops a value off of the stack, converts it to the type based on the specific instruction used and pushes the result onto the stack.

Instruction Description Binary Format
conv.r.un Converts unsigned integer value on the stack to a floating point number 0x76
conv.ovf.i1.un Converts the unsigned value on the stack to a 1-byte integer and throws exception if overflow 0x82
conv.ovf.i2.un Converts the unsigned value on the stack to a 2-byte integer and throws exception if overflow 0x83
conv.ovf.i4.un Converts the unsigned value on the stack to a 4-byte integer and throws exception if overflow 0x84
conv.ovf.i8.un Converts the unsigned value on the stack to a 8-byte integer and throws exception if overflow 0x85
conv.ovf.u1.un Converts the unsigned value on the stack to a 1-byte unsigned integer and throws exception if overflow 0x86
conv.ovf.u2.un

Converts the unsigned value on the stack to a 2-byte unsigned integer and throws exception if overflow

0x87
conv.ovf.u4.un

Converts the unsigned value on the stack to a 4-byte unsigned integer and throws exception if overflow

0x88
conv.ovf.u8.un

Converts the unsigned value on the stack to a 8-byte unsigned integer and throws exception if overflow

0x89
conv.ovf.i.un Converts the unsigned value on the stack to a native sized integer and throws exception if overflow 0x8A
conv.ovf.u.un Converts the unsigned value on the stack to a native sized unsigned integer and throws exception if overflow 0x8B
conv.ovf.i1 Converts the value on the stack to a 1-byte integer and throws an exception if overflow occurs 0xB3
conv.ovf.u1 Converts the value on the stack to a 1-byte unsigned integer and throws exception if overflow 0xB4
conv.ovf.i2 Converts the value on the stack to a 2-byte integer and throws exception if overflow 0xB5
conv.ovf.u2

Converts the value on the stack to a 2-byte unsigned integer and throws exception if overflow

0xB6
conv.ovf.i4 Converts the value on the stack to a 4-byte integer and throws exception if overflow 0xB7
conv.ovf.u4 Converts the value on the stack to a 4-byte unsigned integer and throws exception if overflow 0xB8
conv.ovf.i8

Converts the value on the stack to a 8-byte integer and throws exception if overflow

0xB9
conv.ovf.u8

Converts the value on the stack to a 8-byte unsigned integer and throws exception if overflow

0xBa
conv.i Converts the value on the stack to a native sized integer 0xD3
conv.ovf.i Converts the value on the stack to a native sized integer and throws exception if overflow 0xD4
conv.ovf.u Converts the value on the stack to a native sized unsigned integer and throws exception if overflow 0xD5
conv.u Converts the value on the stack to a native sized unsigned integer 0xE0

unbox

Pops a reference-type value off of the stack, unboxes it as the specified value type and pushes the result onto the stack.

Instruction Description Binary Format
unbox <type> Unboxes the value on the stack as the specified type 0x79 <T>

Ckfinite (ChecK INfinITE)

Pops a floating-point value off of the stack, checks if that value is Not-A-Number or infinity and throws an exception if it is, otherwise it pushes the value back onto the stack.

Instruction Description Binary Format
Ckfinite Throw exception if NaN or Infinity 0xC3

Now that we understand that basic instructions used to generate programs we can pull back and start looking at how programs are structured.

2019-06-15 - Abstraction is Magic

There's a saying in scientific circles about standing on the shoulders of giants. The idea being that what people are working on today is based on the knowledge gained by those that came before them. If everyone was starting from scratch then we'd never make any progress. Programming is the same way but our currency of progress is abstraction.

Abstraction is the idea of hiding details so that it's easier to focus on the bigger picture. When programming first started everything was done in machine code with the programmer telling the processor the exact actions to perform. This allowed absolute control and the possibility of extremely efficient programs but it also required the programmer to be very aware of the intricacies of the processor and it took a lot of work to develop a complete application. The invention of compilers allowed the details of the processor to be abstracted so that the programmer could focus more on the specifics of the application they wanted to create. The developers of the compiler still needed to know about the processor but their work allowed others to focus on bigger issues. Successive generations of programming languages and advances in operating systems and framework allow even more abstraction.

But abstraction is a double edged sword. It helps you to focus on the bigger picture and ignore the small details until there's a problem with those small details. It's really nice that the operating system has a mechanism for creating a dialog box until there's an issue creating that dialog box and the OS won't tell you want it is or how to fix it. When you are writing machine code there's never a situation where the processor does something you didn't explicitly tell it to do. The more abstractions you have the more things that are going on behind the scenes that you are not aware of. You also have less control over how exactly things work. When you are doing everything yourself it's easy to optimize operations to be very efficient for your specific case. Abstractions need to be general enough to meet a variety of needs so they may end up doing things that aren't required for your specific scenario.

I think the important thing here is that abstractions are required for programming to advance but we can't lose sight of what those abstractions are doing. You need to understand your abstractions to some degree if you are going to be successful at using them. This is the main thing that drives me to learn about assembly language, intermediate code, and compilers. I will likely never do anything with those concepts professionally but knowing them helps me work with them as abstractions.

Prev page

5 6 7 8 9

Prev page