Programming thread

  • 🐕 I am attempting to get the site runnning as fast as possible. If you are experiencing slow page load times, please report it.
Cool, I'll play around with this.

I saw suggestions elsewhere online to use a class to deal with the UI, but every tutorial out there seems to give such unhelpfully trivial examples of classes ("Dog" and "Cat" are members of the class "Animal", etc.) that I couldn't figure out how they'd actually be applied in a real program.
For example, suppose Label is UI component that simply displays a piece of text, you could make a subclass CalcScreen that that displays the calculator screen and handles the specific logic of formatting the text. Generally a superclass is a more general type, and a subclass is a more specific type. The advantage of subclassing is that you can reuse the functionality of the superclass between subclasses.

Python:
# the actual project is in C#, so it translates a little awkwardly

class IControl: # represents a control source, like a button press or mouse movement
 @abstractmethod
 def getSubControlCount(self) -> int: # controls may contain sub-controls
  pass

 @abstractmethod
 def GetSubControl(self, id:int) -> IControl:
  pass


class IDigitalControl(IControl): # represents a control with a boolean value
 @abstractmethod                        # such as a button, or joystick direction
 def getValue(self) -> bool:
  pass


class IKeyboardControl(IControl): # represents a keyboard
 class KeyControl(IDigitalControl): # individual keys of the keyboard are sub-controls of the keyboard
  def getValue(self) -> bool:
   #...
 
 def GetKey(self, key:IKey) -> KeyControl: # get a key matching `key`
  #...

 def getKeyCount(self) -> int:
  #...


 def getSubControlCount(self) -> int: # implement the IControl class
  return self.getKeyCount()
 def GetSubControl(self, id:int) -> IControl:
  return self.GetKey(id)

class WindowsKeyboardControl(IKeyboardControl): # A specific kind of keyboard, with a windows layout
 #...
Basically a IControl represents a user input source very abstractly, and all it specifies is that a control may contain other controls. IDigitalControl is a little more concrete, it represents an input like a button that may be on or off. IKeyboardControl represents a abstract keyboard with no specific layout. WindowsKeyboardControl represents a keyboard with a windows compatible layout.

By making WindowsKeyboardControl a subclass of IKeyboardControl, we can use WindowsKeyboardControl interchangably as a IKeyboardControl, the advantage of this is that our code can deal with keyboards without having to depend on the specific layout. Another advantage is that since both xbox facebuttons and keyboard keys are IDigitalControl we can use them interchangeably in our code;
Python:
class IKey: # a set of singletons describing keyboard keys
 class Alpha(IKey):
  global a = Alpha('a')
  global b = Alpha('b')
  #...

 class NumPad(IKey):
  global num0 = NumPad('0')
  global num1 = NumPad('1')
  #...

class XBoxController(IControl): # control representing an xbox controller
 class FaceButton(IDigitalControl): # control representing an individual facebutton
  def getValue(self) -> bool:
   #...
 xButton = FaceButton(...)
 #...

#...
# define a "behavior" that will use our controls


class MovementBehavior: # a "behavior", which can be added to an Entity
 def __init__(self, speed:float, forward:IDigitalControl, right:IDigitalControl):
  self.speed = speed
  self.forward = forward # since forward and right are digital controls, any kind of digital control can be used
  self.right = right

 def Execute(self, target:Entity): # periodically called by the game loop
  forwardAmnt = self.forward.getValue() ? 1 : 0
  rightAmnt = self.right.getValue() ? 1 : 0 # poll the controls

  moveVector = Vec2(forwardAmnt, rightAmnt) * self.speed
 
  target.Move(moveVector) # move a certain amount based on the controls

#...
# keyboard and controller defined in the start up code

myPlayer = Entity() # create a new entity and add our behavior
myPlayer.AddBehavior(MovementBehavior(0.5,
 keyboard.GetKey(IKey.Alpha.w), # move forward with 'w'
 controller.xButton)) # move sideways with x on the controller
In this example we have an object myPlayer that moves depending on button presses, but since our buttons are all IDigitalControl we can use buttons from anything be it a joystick, a controller, a mouse, or a keyboard. Having a superclass creates a symmetry between our types which allows a lot of code reuse.


In my opinion a proper example of an unfairly maligned language feature would be goto. It's common beginner advice that you should never use a goto, but that is simply cargo cult foolishness. Gotos are a good backup tool for when prettier control flow fails;
C#:
// A function which attempts to find a node matching a key within a binary tree
// that may be concurrently modified. If a node is removed while our function
// is visiting it then we will need to restart the search.
bool TryFindTreeConcurrent(Node start, Key target, out Node result) {
RETRY_TOP:
 var cur = start;
 while (CheckValid(cur)) {
  if (!TryReadKey(cur, out var curKey) // Try to get the key of the current node
   goto RETRY_TOP; // May fail due to datarace

  var cmp = Compare(target, curKey);

  if (cmp < 0) { // If our target was less than the current node
   if (!TryGetLeft(cur, out var left)) // Try to get the left node
    goto RETRY_TOP; // May fail due to datarace
   cur = left;
  } else if (cmp > 0) {
   if (!TryGetRight(cur, out var right))
    goto RETRY_TOP;
   cur = right;
  } else { // Found our target
   result = cur;
   return true;
  }
 }
 result = invalidNode; // Return false if either no node matching target exists, or start no longer exists
 return false;
}


//...

// Refactored to remove the goto
bool TryFindTreeConcurrent(Node start, Key target, out Node result) {
 while(true) {
  var cur = start;
  bool retry;
  while (retry = CheckValid(cur)) {
   if (!TryReadKey(cur, out var curKey)
    break;

   var cmp = Compare(target, curKey);

   if (cmp < 0) {
    if (!TryGetLeft(cur, out var left))
     break;
    cur = left;
   } else if (cmp > 0) {
    if (!TryGetRight(cur, out var right))
     break;
    cur = right;
   } else {
    result = cur;
    return true;
   }
  }
 
  if (!retry) // If the inner loop breaks, retry will be true
   break; // If the loop condition fails, retry will be false
 }
 result = invalidNode;
 return false;
}
The version with the label is plainly easier to understand; if a data race occurs, retry from the top. The "improved" version —despite lacking the scary no-no word— is much more complicated; if the inner loop condition fails, retry will be false and the retry check will break, but if the inner loop breaks, retry will be true since the inner loop condition must have been true, therefore the outer loop will continue. Not only is this harder to understand, it's also slightly less efficient since an extra jump must be performed.

Stackoverflow geniuses will tell beginners to avoid goto at all costs, and as a result you end up with exceptions as a means of breaking out of multiple loops and other such haram behavior.
 
Last edited:
Are you seriously suggesting using global variables in place of locals?
Yes. Abolish all local variables. All memory should be global. Do you really need all those single use ints? No. Local variables and scope are handholding for babies. Real programmers create a program using a single multipurpose word. What, you need more than 8 bytes of memory? Excuse me your majesty, just take it all while you're at it if you need so much.
 
Memory is cheap these days, so I just store all 256 possible ints in memory upfront and just use the one I need as I need it rather than creating a new one each time.
See, this guy's thinking like a programmer. Memory unused is memory wasted. Plus when you have globals like Value2426380, you always know exactly what you're getting. It's unambiguous and easy to debug. Saves loads of CPU cycles too.
 
The best part is that if you ever need to redefine 6 to 7 you can just do it live without taking the system down for a recompile, just by attaching a debugger and editing the global values.
Real Programmer Seymore "Seymour" Cray used to have a patch panel built into his mainframes where he could just rewire this on the fly.
 
not sure whats up with me but I do recursive when I just want to quickly do an algorithm and I don't really care about efficiency that much. I find it a lot easier to think about most of the time than writing in terms of loops. I think it's just because it has a really limited "depth" that you have to go to prove it works, ironically. In general, I find induction to be the easiest form of math proof to think about.
 
Google does the same joke:

https://www.google.com/search?q=recursion
google_recursion_gag.png
 
not sure whats up with me but I do recursive when I just want to quickly do an algorithm and I don't really care about efficiency that much. I find it a lot easier to think about most of the time than writing in terms of loops. I think it's just because it has a really limited "depth" that you have to go to prove it works, ironically. In general, I find induction to be the easiest form of math proof to think about.
Some problems are naturally hierarchical and recursive. For example searching a tree or recursively dividing space. Other problems aren't really recursive, such as do something x times, but it is maybe easier to think about high level functions like map and reduce than over individual elements.
 
Somehow Delphi is ranked #14 on the TIOBE Index, and even went up from #19 last year, which I think says more about how worthless that index is than how worthwhile a language is to learn.
This shit doesn't even have MUMPS listed in the top 50. It's just buried under there.

Oh did you think MUMPS was dead? Where we're going, we don't need eyes to see.
 
Memory is cheap these days, so I just store all 256 possible ints in memory upfront and just use the one I need as I need it rather than creating a new one each time.
I just create a lookup table for the set of inputs for every single function I have. What else would you do? Memoize everything. Do you know how much time you could save by memoizing user input? getchar() will always return "h" and that's how it should be. End users impede software performance. Just get rid of them.

The theoretical worst-case time complexity of a user input is infinite. That is unacceptable. Fuck em.
 
Back