(Also there might be some inconsistency in the post. This might be just ranting)
BYOND was my first Object-Oriented language. Before that I had tinkered around with BASIC-variant languages. The differences between these two are their paradigms. BYOND uses the object-oriented approach, whereas most BASIC-styled languages use the imperative approach. What are the differences between the two?
Imperative:
- Mainly based on functions and subroutines
- Most entities are defined on the global scope
- Top-down language
- Code flow is easy to understand
Object-Oriented:
- Organized structure of code
- Inheritance, polymorphism, object trees, etc.
- Objects can contain fields and methods
- Event-based
I started late as a programmer (around 17-18). I guess it just didn't really click for me until I tried out a little program called Play Basic. It started to make sense to me because code was extremely easy to understand at the time. The top-down approach made it look like I was reading a script.
When I started using C++, BYOND, and Java, I was awakened to the world of OOP. But I had a really hard time with it (and still do). It's great to think of things as objects and allow them to have methods and variables attached to them, and OOP makes use of scopes in an excellent way so that objects and variables outside of the scope naturally get deleted.
Biased argument starts here.
What I have a hard time with, however, is defining large object trees, and subtypes in which there's many different types (like creating 100 different swords, for example). In BYOND especially, if you'd want to use the map editor for most things, you'll need to define it as an object derived from /atom first. Only then would you be able to place it on the map.
I cannot seem to grasp object-oriented programming because I feel like objects should be much more flexible. I feel like making subtypes of subtypes of objects is very confusing . Variables (in most languages) are rigid. Once the code is compiled, variables cannot be added or removed. Same goes for methods.
In a procedural language, defining an object and manipulating it would look something like this:
var d = CreateItem()
SetItemName (d, "Fancy Necklace") // no type casting necessary here
SetItemValue (d, 100)
Print (GetItemName(d))
In an object-oriented language:
item d = new item()
d.name = "Fancy Necklace"
d.value = 100
Print (d.name)
The neat thing about the procedural paradigm is that data doesn't have to be stored in an object. It can be stored in arrays and lists. Object data can be structurally organized into lists of lists as well, which makes the "object" malleable. data can be added and removed from it as well.
This sort of stemmed up from making this little thing. I wanted an object that was easy to work on, and I could grab data from it without needing to create a type in code for it. Not only that, but it saves to plaintext and I can edit the data as I see fit. And then I realized I really missed working with Basic-styled languages. because object-oriented aspects were added simply to SUPPORT the platform instead of being the foundation of it.
I often have a hard time finishing a project simply because I don't know how to program it in object-oriented style. That, and I guess I just dislike the way code looks using this method. It seems restricting to use objects for everything. But don't get me wrong. There's a lot of things about this paradigm that I absolutely love. For example, objects are great for holding data in a structured manner. "Item.name" in the exmaple above is a perfectly acceptable field. I just don't like when object trees happen to get too deep like:
Item -> EquipItem -> Weapon -> Sword -> SomeSword1
While SomeSword1 still retains the "name" variable, it suffers from being a child object so specific that I'd need to do the same thing for all other similar objects:
Item -> EquipItem -> Weapon -> Sword -> SomeSword1
Item -> EquipItem -> Weapon -> Sword -> SomeSword2
Item -> EquipItem -> Weapon -> Sword -> SomeSword3
...
What say I don't like the long type path (and we'll just say we're using DM in this case):
Item/EquipItem/Weapon/Sword/SomeSword1
If I wanted to initialize this item:
proc/GetSomeSword()
return new/Item/EquipItem/Weapon/Sword/SomeSword1()
Even if I happened to use parent_type to shorten the type path:
Item
parent_type = /datum // redundant, but shown here for consistency.
EquipItem
parent_type = /Item
Weapon
parent_type = /EquipItem
Sword
parent_type = /Weapon
SomeSword1
parent_type = /Sword
mob/verb/EquipSword()
contents += new/SomeSword1()
What if I decided to use the imperative approach?:
item
var/name = ""
var/subtype = "" // multi-use string that contains the "type" of item.
var/list/variables = list("something"=1, "anotherlist"=list()) // associative list to hold object data.
proc/CreateItem(N="SomeItem",S="helmet")
var/item/i = new()
i.name = N
i.subtype = S
return i
proc/EquipItem(mob/M, item/I, S)
if (I.subtype == S)
M.equipslots[S] = I
TL;DR: I like Imperative over Object-Oriented.
I enjoy a mixture of the two.