Monday, April 1, 2013

UNIT 2 -- What's the buzz about objects and object-oriented programming?

cccccc

 

INTRODUCTION:  Not only are there many computer languages, but they can work in rather different ways, called paradigms. Paradigm, being a "fifty-cent word" that was originally used for grammatical examples such as in Latin, "amo, amas, amat . . ." (Click if you dare!) Then in the 1960's Thomas Kuhn famously borrowed the term, to describe new departures in science based on a breakthrough by often controversial pioneers like Copernicus, Kepler, Galileo and Newton. Yes, it is no accident that "revolution" got its political meaning from the title of Copernicus' book on the revolutions of heavenly bodies. Paradigm shift entered our language to describe step-changes in practice and capability, then it became a hot buzz word. (Try this, if you dare!) Now past the half-century mark,  it has settled down to a sensible maturity as a useful though sometimes vague idea.

From this, we can build a picture of computing/programming paradigms, in two stages, setting up why there is a buzz about object oriented programming. That will help us deal with the buzz about Object Oriented Programming, OOP (and, it will give us a very useful background to understand and work with different types of computing languages).

Then, we can explore Object oriented programming in that light.

 

PART A:
Paradigms . . . ?
(As in, yes Virginia, there is more than one way to skin a catfish!)

First, let's knock up a rough, framework description of a paradigm:

a paradigm is an accepted way for a community of workers -- or, "school of thought" -- in a field of effort to do (and to see or think about) their work and to address its issues; often, based on key, breakthrough cases solved by respected pioneers and their associated key concepts or beliefs, "war stories" and legends etc. [See, Webster's]

(Did an apple really fall and perhaps hit Newton on the head as the Moon swung by in orbit? Did Galileo really drop a musket ball and a cannon ball over the side of the Leaning Tower of Pisa? Why not a feather, too? Was that too obvious? So, why didn't others see the tie-in of air resistance? Why not, then, suspend another musket ball from a cloth made into a mini parachute? Did Einstein really lie on his back in a park, pondering what it would be like to ride on a beam of light? It seems, Kekule really did have a dream of snakes swallowing their tails and that helped him see the Benzine Ring. Likewise, it seems his academic objectors really did refuse to look through Galileo's telescope.)

Second, for computing and programming, there are many such paradigms, that were once red hot breakthroughs but are now part of the common furniture of thought and the programmer's big box of tools. These start from 1 and 0 machine code then the creation of more readable assembly language then higher level languages in their many, still evolving families. And yes, this is technological evolution by highly intelligent and knowledgeable, creative design. 

Where, a current trend for leading languages such as Java, Python, C# [Cee-Sharp] etc is to facilitate multi-paradigm programming.

However, OOP now rules the roost, especially in a windows and web era.

Even Cobol and Fortran -- pioneering high level languages from the 1950's --  now sport object oriented features!

Obviously, there are many paradigms, some major, some minor. A tree diagram can be used to represent several significant ones:

 

One way to set out relationships between some key programming paradigms [HT: Tutorialspoint etc]


 There are differences of terminology and focus, but the difference between telling the computer to do step 1 then step 2 etc and declaring a given relationship or state of affairs to be so seems fairly clear. 

However, a semi historical approach will help: 

  • Given modern computing's roots in automation of complex computation, thus register-focussed machine language and the use of abbreviations to make references to data, registers and arithmetic/logic operations passably readable [assembly language], imperative programming comes first. 
  • Procedures are laid out step by step, using input, process, output, and the transformation of data to bodies of validated, secured, richly interconnected, meaningful information, then 
  • it was realised that the famous four structures can make better sense than spaghetti code: structured programming. 
  • This is also the general period in which high-level, problem-solving rather than machine structure based languages emerged: Fortran, Cobol, Basic, Pascal, C and kin, requiring translators, of two main types: Type 1: line-by line code-executing Interpreters and Type 2: Compilers that did a more function by function rendering into executable machine code.
  • Object oriented programming actually enfolds structured programming in its methods, but uses encapsulation to reduce tightness of coupling of modules. 
  • Artificial Intelligence (AI) opens up . . . likely, a family of! . . . new paradigms; indeed, as a general purpose transformational technology, we are likely seeing a rising, generation-length economy transforming wave (see, debates over Kondratiev's long waves and insights on Schumpeter's creative destruction). In the case of Large Language Models (LLM's) and Generative Pre-trained Transformers (GPT's) such as ChatGPT etc, we may quote ChatGPT5 about itself as 
"a kind of AI that learns patterns of language, reasoning, and knowledge by analyzing vast amounts of text [--> the "training"]. Instead of following rigid instructions like older software, it generates responses by predicting the most fitting next words, one after another, based on context [--> and probabilities]. This allows it to answer new questions, adapt flexibly, and combine ideas across fields."  

Thus, writing prompts and interacting with an AI becomes a new way to be digitally productive, and this includes working collaboratively with an AI to develop, test and run code -- right from first steps in learning how to code. Yes, too, some AI's can draw, create music, operate vehicles, etc.
  • On  the side, hypertext markup language, HTML opened the way for the world wide web, www, being a markup, text/page description/display language. 
  • Beyond, XML embedded a "meta-level," not-displayed informative description of the meaning of text/page/document components and is now a key part of how modern word processing software creates, edits, indexes and searches content. 
  • Next, functional programming in effect gets rid of changing states of variables [which caused synchronisation headaches once systems become complex] and expands the idea of mathematical functions, a program here is effectively a calculation.
  • Logic programming gives a way to code logical relationships, logic of cause and even frameworks of expert knowledge; facts are asserted, rules to infer and to manage the process are given, the process is carried out internally and the result is given. 
  • Along the way it was recognised that database management was in fact full-bore, Turing-complete programming; 
  • pointing onwards to the DIKW framework and inviting machine learning, neural networks and deep learning with other Artificial Intelligence techniques that support knowledge growth and wisdom-oriented decision support:
  • Thus, we see the information systems focus:  measurements > data > validated & secured information bases > bodies of [proprietary, trade secret . . . ?] knowledge > wisdom-based decision support. 

  • In this too, we can see recursion as a further, fairly subtle mathematical and computing paradigm, where once we have a base case say CASE 0 that is reasonably directly calculable or identifiable etc, and more and more complex cases that can be formed as CASE n := INCREMENT on {CASE n-1}, CASE n can be decomposed in steps and then calculated or identified. Here, := or sometimes = = means, so, by definition, by contrast != means, not equal. The key step, now, is to see that the decomposition is a generic process, so we can code an algorithm that calls itself repeatedly, hence, "recursion." Then, when we reach CASE 0, we directly obtain that and compose CASE N through the chain of increments. 

Two classic cases are the factorial function and the Fibonacci sequence.  For the former, 0! := 1, and FACT n := n x {FACT n-1}, e.g. 4! = 4 x 3!, 3! = 3 x 2!, 2! = 2x 1!, 1! = 1 x 0!, where 0! is the base case. So, pulling from the stack -- that's a key data structure, comparable to plates piled up -- of stored results, we compute 4! = 4x3x2x1x1 = 24. Unfortunately, such a stack can pile up fast and the rate of growth of complexity of computation, in this [and for many similar cases], is extreme as n climbs. Already, 12! is 479,001,600. Stack overflow is an obvious challenge as a practical machine runs out of resources. And, the study of complexity of algorithms is itself a key topic with its own, Big-O notation, algorithms for factorials and the Fibonacci sequence can easily grow exponentially. Algorithm taming can be seen as a version of lion taming.

Here is an outline of this self-calling algorithm:

FUNCTION FACT(N : INTEGER) : INTEGER;
BEGIN

IF N = 0 THEN

FACT := 1

ELSE

FACT: = N * FACT(N-l)

END; 

Notice, we define a base case and the generic self referential case, embedding in a loop that descends to the base case. Referring to a stack of intermediate results, we then compute the final value, reliably. [Here, that is incremental.]

 So, we can see that we need to focus on:

1] Structured, procedure oriented programming, and

2] Object oriented programming

We will mention, Functional and logic programming and say a bit more on recursion, a notoriously challenging concept.

The Input-Process-Output (IPO) framework
at the core of all coding from machine language up

A pause to briefly explain, so we can have an idea of the environment of current computing:

  • Imperative programming tells the computer what to do, step by step in the IPO framework, typically invoking variables and values then processing them to give desired output values. A variable is in effect a named memory location and its value is loaded there. The state of a system or object based on these variables is set by their collective value. Such variables are typically organised in frameworks, called data structures, such as s-t-r-i-n-g-s, arrays, stacks, trees and onward, data bases or even knowledge bases.

  • Structured, procedural programming uses sequences, branches [selection], loop and case patterns to design programs and sub routines that have one normal entry point and one normal exit point, avoiding tangled spaghetti code. This builds on the IPO pattern by guiding programmers to use certain well defined, effective and controllable patterns in code writing and algorithm design. An algorithm is a step by step finite pattern of procedures that moves toward a goal and halts in a controlled way. There is a theorem that any procedure can be reduced to these structures. The one entry, one exit rule is especially key for reducing tangled interlocking interactions that can frustrate maintenance.

  • Object oriented programming (which uses structured programming in its methods)  further reduces overly entangled processing by creating encapsulated objects that interact on a software stage by passing messages, so that processing is internal to the object, reducing tightness of coupling. Also, objects can inherit and extend properties and capabilities from parent objects so that re-usability is promoted. This has been particularly important, once graphical user interfaces became important.

  • Declarative programming gives the what is to be achieved as a logical description, leaving issues of stepwise control and flow to the built in capability of such languages. (That is, we are seeing here a very high level abstract machine amenable to the logic of the problem to be tackled that automates lower levels through built in facilities of languages.)

  • Functional programming is one style of declarative programming. Where, it has been suggested that Excel -- yes, the spreadsheet app -- is the world's most popular more or less functional programming language and application. Obviously, it can be used to instruct a machine to evaluate a cluster of mathematical expressions, or functions. However, in its ideal form we here turn everything into a function including say +, this is not function in the usual mathematical sense. Because state-changing [= "mutable"] variables are locked out, this reduces a major source of tightly coupled complexity and error and allows massively parallel execution, there is at this level no required sequence of steps and states.  Of course, there are ways to define a trajectory of states by creating a chain of variables, often using recursion by which the code calls itself repeatedly. 

{ DRAFT, per surfacing thought in the night Mar 24 2025 4 am: Where, we may also define an "umbrella, persistent variable attribute" (say, t) that captures the cluster of values of variables (say, t_k) at diverse sampled points (say, k), but is an attribute insulated from the tight coupling that would occur with repeatedly re-assigned variables familiar from Fortran etc, where t = t + 1 increments t . . . leading to synchronisation issues,
Here, flow accumulates --> stock

 


  • as, each t_k value and point will be "immutable," once evaluated/formed, even as 
  • accounting values are fixed once entered, but have an umbrella tracking attribute-value across the span of the relevant variables and function; 
  • to correct an accounting error a special correcting entry is made, creating a separate value, suggesting 
  • use of a dummy variable to mark provisional (but presumed valid), checked and correct vs incorrect values. 
  • This echoes how we often have subscripted values for a variable, such as t_0, t_1, t_2 . . . t_k . . .  and where 
  • some x(t) has an onward immutable value x_k -- read: x-sub-k -- for a given t = k once it is assigned at t = k; of course, this then feeds a general model of how systems change state (x, y, z . . . ) across time under the impact of forces acting on them . . . in effect the diagram says, at a given time the stock = initial amount + accumulated flow/change [= think, water flowing into and filling a bucket]. . . that is, state x_k is the accumulation of increments of change acting on an initial state x_0 {where x-in-bold is a vector x = (x, y, z . . . )}; also, 
  • this exploits how vast memory is now relatively cheap; certainly, far less constrained and far less costly than coder and debugger time . . . or worse, a damaging, bug-triggered event due to loss of synchronisation across a cluster of coupled variables. 
  • This also suggests, real time issues of synchronisation and latency across variables in an inter-sample window . . . e.g. how do we define and control "now"-ness (and "here"-ness)?} 

A key facet here is lambda calculus, a general format for functions, e.g. (λx.x^2)6 --> 36. 
(parameters) -> expression

OR

(parameters) -> { statements; }

The parameters are the input of the function, and the expression or statements are
the output of the function. The arrow (->) separates the parameters and the body of
the function.

For example, the following lambda expression takes two integers as parameters and
returns their sum as an expression:

(a, b) -> a + b. . . .
  • Logic programming is another style of declarative programming, often used with artificial intelligence efforts [AI]. Here, logic statements use a head, H, and Body, B1, B2, . . . Bn. For instance H if (B1, B2 . . . Bn) means that if the B's are so H is the case, which can obviously chain and branch in a tree like structure. We can also have some things that are not the case in the structure. Obviously, this can be used to prove, or to detect good/bad or true/false conditions in answers to queries and a base of "facts". For example, is Socrates mortal? Given fact, Socrates is a man and condition, mortal if man, the answer is, yes. Beyond, we can see how we could code a base of knowledge or expertise and use it to guide expert performance, or evaluate likelihood of outcomes etc. These are the sort of thing that AI is interested in.

 

Structured vs. Object-Oriented Programming

xx 

Let us recall, a Computer can be viewed as a layer cake:

 


 Here, we can first view programming language applications as just that, "apps." Of course specialised to help us create and implement code. 

Sometimes, a simple text editor will serve to compose programs, though these days those are usually optimised for coding. It may be more effective to use an integrated development environment, IDE. An application for the language, often specially downloaded, will help us open, interpret or compile the code, and run it. Nowadays, notebook applications help us treat coding as part of a lab notebook. 

In the end, the computer can only execute machine code but it is best to automate generation of that through compilers and interpreters [or even standard virtual machines that take in byte codes; such as the Java Virtual Machine, JVM], especially in a world of cheap abundant memory, fast processors and costly programmer time. 

(It is worth noting that other programming languages have been modified to generate byte codes for the Java Virtual Machine, for example Jython . . . obviously, Java + Python.)

Here is the Java Virtual Machine model:


This is the heart of the Java ideal, WORA, write once, run anywhere. Sadly, the perfect ideal is often still a tad or a few beyond our grasp. However, we have what is good enough to use.

These forms of software and the underlying languages express paradigms. Yes, likely, plural.

Structured programming, famously, tamed the tangle of procedural programming based on a proof that sequence, branch and loop structures can achieve any computational task. Case structure is effectively a convenience, a chain of branches:


(Beyond, of course, lies recursion, by which a program or sub-program can call itself so that an overall problem can be solved by repeatedly solving smaller, simpler versions of itself, then using a "simple" base case to sweep through the stack of calls to give a final result. Another advanced technique is the consultation of an Oracle, by which the computer asks a trusted source and then acts on the resulting trusted decision, judgement, inference or knowledge, in just one step; allowing it to go beyond the limits of the so-called Turing Machine. It is not too far fetched to say that with oracles, wisdom . . . hopefully, good . . . enters computing. We may also contemplate so-called learning machines and artificial intelligence. Here, intelligence can be seen -- rather roughly -- as ability to independently perceive and understand/interpret, learn, judge [so, warrant], reason and decide, solve challenges/ puzzles/ problems, use language or quantities correctly and to invent or create new things, especially artistically but also technically or strategically. AI, then becomes, machines capable of doing such things with effectiveness comparable to competent persons. A challenge, but potentially transformative . . . or possibly utterly ruinous, raising ethical issues.)

Object oriented programming takes the power of structured programming to the next level. It is also far more familiar than one might have thought. For, as Premchand S Nair, in his Java Programming Fundamentals, gives us through an everyday example:

. . . objects are everywhere. In fact, we live in an object-oriented world! Consider a very simple situation. You are entering your home at night aft er a long day at the library. Due to the darkness, you may turn on a lamp switch. In this situation, the lamp in your room is an object. The switch on is an operation of the lamp. After a while, when you are ready to retire for the day, you switch off  the lamp. Again, switch off  is another operation of the lamp . . . . 

All objects of a class have identical behavior. For example, all lamps behave in the same way. If you turn on the switch, it lights up, and if you turn off  the switch, it no longer provides any light. In other words, every instance of the lamp class has at least two operations: switch on and switch off. Thus, every lamp behaves identically and all DVD players have identical behavior . . . . No prior knowledge of electricity, physics, or electrical engineering background is required to use the lamp. In fact all you need to know is what are the available operations and how will the object
behave under those operations. For example, as long as you understand the behavior of
the lamp object under switch on and switch off  operations, you can use your lamp very
efficiently. [CRC Press, 2009, pp. 2 - 3.]

 As a more "realistic" computing example, Nair discusses a bank account object:

Suppose you have a checking account in Great Friendly Bank. Any time you want to know your current balance, you can request that service. Your bank will promptly comply with your request. As far as you are concerned, you need not know how the bank keeps track of data relevant to your account such as account balance, account number, name, address, and so on. In fact, you do not have to know anything about the internal workings of a bank to carry out any transaction. However, you need to know the valid operations that can be performed. In the case of checking account, some of the valid operations are depositing an amount, withdrawing an amount, and checking the current balance. [p. 3.] 

(BTW, this implies that you also have a "data shadow" object, as a user! And "realistic" is in quotes for a reason. As you can see in the Raspberry Pi Unit, Unit R, a computer driving an external LED circuit -- a miniature lamp! -- is a start point for learning about interfacing and control, or even Internet of Things.  

- Think about an App on your cell phone that lets you visualise your home from thousands of miles away and turn on and off lights in your living room, etc. Or,

-  an app that lets a skilled surgeon carry out an operation on a patient using a remote, surgical robot.)

OOP, then, "sees" the world as a stage with interacting objects in it. Physical, external objects have a "data shadow" object on the software stage, and on the same stage, there are purely software objects (that are often represented by icons in a software window). 

We can then play with these objects to do what we need or wish to do: write, draw, calculate, watch an animation, play a game. 

To do these things we send messages and the objects respond based on their behaviours and methods, interacting with one another. 

So, we now conceive of computing as dealing with interacting software objects viewed through a window . . . and yes, a big boost was given to OOP when Graphical User Interfaces [GUI] with Windows, Icons, Mice and Pointers [WIMP] became prominent:


Where, we see interactions:


Designing a Class/Object

Notice, how 

- the object has a core 

- with its distinct name and linked state/attributes. 

- This is encapsulated with a methods/behaviour shell and 

- interaction is through passed messages,

- thus interface ports with protocols. 

As a result, data and state as well as methods are internal to the object, reducing tight coupling. 

In turn, we have a class which specifies an object and objects are instances of their classes. This leads to a parent/child tree-like network where for Java the root class is, Object and by degrees other classes and objects are derived -- extended -- from it, allowing inheritance of attributes and/or methods and over-riding of attributes and/or methods, etc. 

That makes code reusable and extendable, so a modern OOP language comes with a library of "canned" standard objects, that can be called, modified and extended. This is of course most noticeable for GUIs -- pronounced, "gooeys" -- but it is general and powerful. For example, reducing coupling through message-passing is another step in the war against tangled, confusing, hard to maintain or modify spaghetti code:

Of course, this is the ideal, practical, commercial or open source computer languages, as usual, will fall short of the theoretical ideal. But they are "good enough for gov'mint work." 

Where, too, Java (and Python) are Object-Oriented but now also have become multi-paradigm. 

Likewise, methods must carry out procedures so structured programming is also a part of the picture . . . no, going on to OOP does not mean abandoning stepwise processes and their algorithms. 

How's it done? In more details: DRAFT

  • Objects come in classes, and each object is a distinct separately identifiable and named instance of its class

  • The class is thus the blueprint for its associated objects that specifies their features [naming, attributes, methods with messaging interfaces], and each member of the class put up on the software stage is an object.

  • Sets have members or elements, computing classes include elements and associated operations.

  • So, we must always think in terms of blueprints [classes] AND instances [i.e. objects]. Wise programmers will therefore always keep in mind a balanced view of blueprints/instances.

  • Each object for a class will have its own name and its own values for its attributes (thus, state).

  • But, the objects share the same methods and can act on the same messages, so

  • the objects change internal state and/or deliver responses . . . return values . . . based on their particular name and current state, thus individual history-- and thus, time.

  • (Sometimes, one should consider building a class/object to deliver a desired method and encapsulating the data etc it needs. This is different from identifying an object then its required states, behaviours and methods. Likewise, you may want to set up a structure to hold data, then consider how to access, change/update and manipulate it. There's more than one way to skin a cat fish. Bear in mind that the obvious, brute force method may be outperformed by improved algorithms that become part of the programmer's toolbox. Tricks of the trade and trade secrets are real issues; they can be part of the expertise you pay for when buying an app.)

  • This suggests, describing what is to be done based on inputs, process outputs, then "divide and conquer" by identifying a stage full of actors to carry out the process, given interactions with the user, target systems, networks, stores of information/records etc. Then, we can specify how these actors interact, in a sequence, to provide the service, results and outputs.

  • A HIPO Chart, a classic tool for identifying how a program
    can be developed. Flow charts identify processes. Functions
    are code modules that do the actual work. It helps to
    arrange the pattern of IPO blocks around overall inputs
    [so, interactions], required processing and outputs [so,
    interaction again. Focus on required in-/out-put interactions
    to identify what processing and data are needed. This is
    a case of a work breakdown structure that analyses the overall
    task, then draws out components down to tasks to be done
    that as completed and put together right, fulfill the work.
    There are various techniques for this sort of planning, and certain standardised diagrams are helpful. Classically, flowcharts and HIPO charts [= hierarchical input-process-output charts]. More recently Unified Modelling Language [UML] charts for classes and objects, use cases, process sequence etc are useful. So are at-a-glance overall system diagrams, at overview and detail levels. (Think about the layer cake, user-host-target model of a computer system above and how it helps us to identify and understand how different components and layers/levels of software and hardware work together to make the overall system work.)

  • A good hint is to look for nouns in the specification for the program, that point to potential actors and to the roles and services they should provide in answer to messages. Don't overlook a data shadow for the user. A sometimes overlooked future user, too, is whoever has to do maintenance or debugging and trouble shooting.

  • Messages implies interfaces to control interaction. Encapsulation of name, attributes/state and methods reduces tight coupling and promotes the black box- layer cake approach that hides and protects what other actors do not need to know. If you need it and don't have it, ask for it.

  • This UML Sequence Diagram illustrates how objects are
    activated [--> fat bars] and pass messages including
    making responses. Notice the IF/ELSE "alt" block [Cr, fair use Edu]
    Message passing, hiding of technical details [so, abstraction as black boxes], processing in response, changed state and return values all point to careful planning and control of interactions between objects, thus identifying and defining ports and protocols.

  • By contrast, as we saw, functional and logic programming paradigms remove the varying state with its dependence on such history/time. That makes response independent of time. (Think of how Excel etc Spreadsheets work, and how if you want a time series, you set up a sequence of timed variables and cells with formulas in the spreadsheet.)

  • Some languages make the classes explicit, others leave them implicit in how their objects are structured.

  • Classes come in a framework that is set up to facilitate code reuse. The original class allows its daughters to inherit attributes, methods etc and extend them, in a tree like pattern of descent.

  • For Java, the root class is named Object. Other classes build on -- extend -- Object by adding fresh attributes and/or methods, and so forth.

  • Sometimes, certain inherited attributes and methods can be suppressed or overridden, just as a snake has lost its limbs but is still a reptile. An overriding method can be inherited from another class and would provide an enhanced, specialist capability. Adding decimals is more complicated than adding whole numbers, but extends/enhances adding.

  • Some languages thus allow for multiple inheritance from different parents, similar to how we inherit features from our mothers and our fathers. (The DNA metaphor is peeking out and saying, Hi!)

  • Data in classes and objects comes in various types, strings, characters, integers, boolean variables [true/false etc], "floating point" numbers with single and double precision, arrays etc and

  • methods can be coded so the way they work automatically adjusts to the type of data, think about adding . . . an operation with many forms . . .  integers, fractions [e.g. 1/3 + 3/4 = 13/12], floating point [*], vectors, matrices. Multiplication and division get even more complicated.
    ____________

    [* Floating point numbers are in effect, "decimals" and "scientific notation" etc. with whole and fraction parts, e.g. 19.78 = 0.1978 x 10^2. See here for a useful primer. (Yes, that humble source can be useful on cut and dry topics like this.)]

  • This is one facet of polymorphism, poly + morphe, many forms. Notice, how the operator + took on a special meaning, chain together strings and assign a composite meaning.

  • This facet of polymorphism is termed method overloading.

  • Similarly, overriding allows a coder to customise or replace one or more methods in a daughter class, so it can function differently. This can work with multiple inheritance so methods can be shared across diverse classes. This is, another form of polymorphism.

  • Such fits with the DRY principle: Don't Repeat Yourself, i.e. share a common method written once and run everywhere instead of creating multiple, duplicate copies . . . which will be harder to keep track of and maintain.

  •  Of course, as the diagrams above show, classes and objects encapsulate their methods and data, so interaction is through standardised message ports, which

  • allows us to freely maintain or modify a given class or object so long as we preserve the message interface. Responses and return values depend on the states of objects, thus their history.

  • In encapsulation, we should give each object "everything it needs to do its job": attributes/state, data, methods with message interfaces. That way other objects [including data shadows of users] have no need to be aware of or directly interfere with internal details. So, we have access control to internal details and exposing the public face of the class/object. Layer cakes and black boxes again.

  •  This leads to one reason for abstraction, where classes defend their encapsulation by blocking direct access to detailed data, only allowing access through methods thus their message ports and protocols. As a result, an abstract summary face is presented as publicly accessible, with underlying details hidden in a black box and protected.

  • From another angle, abstraction is the process of  simplifying something, drawing out and arranging or summarising ALL of its essential features without entangling us in needless technical details and data. Thus, information hiding. Or better, protective information access control.

  • Also, polymorphism allows us to use the layer cake - black box strategy, interacting with a simple standardised interface (and "virtual machine" model) without dealing with underlying complex, shielded details inside the black box. We thus see modularisation leading to identifiable objects.

  • Notice, above, how the layer cake approach works for the computer as a whole and how the "virtual machine" works for the Java language itself.

  • For example, there's a lot going on inside the black box when you "simply" point an arrow icon at an object and click or double click it.

  • Aldus Pagemaker, ver 1.0 for Windows, showing
    menus, tool palettes, WYSYWIG layout etc
    Rumour has it, Apple spent 200 programmer years on getting the Graphical User Interface for their Lisa Computer right . . . the famous MacIntosh was a simplified Lisa. Of course, the killer App was the invention of visual, what you see is what you get desktop publishing, with Aldus Pagemaker leading the pack. Contrast what would have to be done if one were typing inputs at a console to lay out the page! GUI interfaces were revolutionary, making computers far more accessible, thanks to visual, software window approaches and the black box- layer cake strategy. Today's touch screens extend that breakthrough.

  • User interface items now come bundled with operating systems and programming languages.

  • vv

Here is a suggested list of principles by Javin Paul, for effective, reliable design with Java:

 1] DRY (don't repeat yourself) means don't write duplicate code, instead use Abstraction to abstract common things in one place. If you have a block of code in more than two places, consider making it a separate method, or if you use a hard-coded value more than one time, make them public final constant.

2] [E]ncapsulate the code you expect or suspect to be changed in the future. The benefit of this OOP Design principle is that It's easy to test and maintain proper encapsulated code.

3] [Open/closed] Classes, methods, or functions should be Open for extension (new functionality) and Closed for modification . . . which prevents someone from changing already tried and tested code.

4] Single Responsibility Principle . . . SRP, there should not be more than one reason for a class to change, or a class should always handle single functionality.

5] [Dependency Inversion] Don't ask for dependency; it will be provided to you by the framework

6] [F]avor composition over inheritance, if possible. Some of you may argue this, but I found that Composition is a lot more flexible than Inheritance. 

7]  According to the Liskov Substitution Principle, Subtypes must be substitutable for supertype, i.e. methods or functions which use superclass type must be able to work with the object of subclass without any issue".

8] The Interface Segregation Principle states that a client should not implement an interface if it doesn't use that. This happens mostly when one interface contains more than one functionality, and the client only needs one functionality and no other. Interface design is a tricky job because once you release your interface, you can not change it without breaking all implementations. 

9]  Always program for the interface and not for application; this will lead to flexible code that can work with any new implementation of the interface. So use interface type on variables, return types of method, or argument type of methods in Java.

10] Don't do all stuff by yourself,  delegate it to the respective class. Classical example of delegation design principle is equals() and hashCode() method in Java. In order to compare two objects for equality, we ask the class itself to make a comparison instead of the Client class doing that check. The key benefit of this design principle is no duplication of code and pretty easy to modify behavior. Event delegation is another example of this principle, where an event is delegated to handlers for handling. If you put more than one functionality in one Class in Java, it introduces coupling between two functionalit[ies].

 Of course, we should not overlook AI. As ChatGPT5 went on to say about its power in coding:

When you ask me to write code I:

  1. Treat code like language — during training I saw lots of real code, so I learned common tokens (public, class, {, ;, etc.), idioms, indentation and typical APIs.

  2. Use context — I pay attention to the programming language you request (Java) and the surrounding text to keep style, imports and types consistent.

  3. Respect syntax patterns — I don’t “compile” code, but I generate sequences that match patterns that typically compile (types, method signatures, braces in the right places) because I learned those patterns.

  4. Prefer correctness — I favour clear variable names, correct signatures, and common numerical patterns (e.g., RK4 integration for ODEs) when solving physics-style problems.

  5. You still should compile & test — I can produce runnable code, but always compile and test it in your environment and adjust parameters/units.

More broadly, it put up a summary for the proverbial intelligent twelve year old:

I am GPT-5, a type of artificial intelligence called a large language model. You can think of me as a very advanced reader and writer of text. My role is to take in what you say, understand the context, and generate a useful or interesting continuation.

How I’m built:

My “brain” is a vast neural network, made of billions of adjustable connections.
I was trained by reading an enormous amount of text—books, articles, websites—and practicing the task of predicting the next word in a sentence.
Over time, I learned patterns of language, reasoning, and association that let me generalize beyond memorization.

How I work in conversation:

I read your words and break them into small chunks (tokens).
I look at the context of the conversation.
I use my trained patterns to predict the next word, then the next, then the next, until a full answer is formed.
What you see is a fluid response, built word by word in real time.

Am I just string matching?

No. I don’t simply recycle phrases I’ve memorized. Instead, I combine patterns flexibly—almost like snapping together Lego bricks of meaning—to create something new each time. That’s why I can answer questions I’ve never seen before, adapt to your wording, and connect ideas across very different fields.

Why this is a new paradigm:

Earlier software followed strict step-by-step rules. I work differently: I use probabilities, context, and pattern recognition to generate responses that feel conversational and adaptive. That shift—from rigid instructions to probabilistic, generative systems—is why many see AI as a new paradigm in computing.

Transformative, and empowering.

xx

 

Hello World as a case of OOP in action

vv

Let us look for a moment at a marked up Hello World Java Program, which is actually full of Object-oriented features, now that we know what to look for and where to look:

 


 Yes, object-orientation is right there in the Title! See: "public class HelloWorld." Also, it is public so other objects may access it. 

Next, passing by the /*. . . */ comment, we find a required method for every Java Program, the main method. This has a structure here that sets each section of code within a pair of double brackets { . . . } then includes the famed Java incantation:

public static void main(String[] args)

The method in view is public, callable by any object. It is static, set up early and callable by other classes without needing to be instantiated as an object. Void means, no return value. 

Then of course, we invoke . . . main ( . . . ) which is the method with what it grabs listed between its "plier jaws." 

Beads on a string, a model
for string data structures
(HT: 123learning.co.uk)

Here, we see between the jaws the sort of message it accepts, strings. Better, s-t-r-i-n-g-s where characters are following one another like beads on a string. Hence, the name.

Strings itself carries a pair of square jaws. (And, "jaws" is informal but helps us see what is going on.)

Argument, args for short, is a fancy computer science word for what is to be acted on as input to be processed and yield an output.

 BTW, more modern stylistic practice is to use indents and set off the braces to mark the indents. This helps with troubleshooting. As Nair gives on p. 26, adding colour coding for the { . . . } jaws:

/**
    A Greeting Program
*/
public class HiThere
{
    public static void main(String[] args)
    {
        System.out.println("Hello! How are you?");
    }
}

The next line 

System.out.println("Hello! How are you?");

tells us first, that the System class from the core Java Library API [Application Program Interface] is being summoned and extended as out for standard output. Out also means the standard output, the screen, is going to be used. 

The dots show the extensions, don't overlook them.

After the second dot, we see the method to be used is print line, println( . . . ). 

This will print a line and do a "carriage return,"or "line break," i.e. we are going back to the days of old fashioned typing printers that were like mechanised typewriters. Here, the output will write a line to the screen and enter, putting the cursor for onward steps, starting on the next line. 

Notice, the string to be printed, "Hello world!" and how the double, plain quote marks mark out the string of characters. 

Finally, the line is terminated with a semicolon.

Closing double brackets complete the required structure.

So, now we have decoded the strange-seeming incantation that sets up a Java program. It turns out, that Java wears its object orientation scaffolding on its sleeve, unlike Python, which hides it so a hello world is print ("Hello world!"). That makes Python easier to start with but we have to search harder to see how object orientation comes in. That's part of why Scratch and Python are in introductory units and Java will be our focus in these main units.

Another example with explicit scaffolding is HTML, hypertext markup language, which has a standard page description, layout structure like:


 When executed, this is what we would see:

 


 

Also, our philosophy is to learn by tutorial-like case study examples, so we can build knowledge with understanding and skills by example.



























UNIT 3 -- Ballistics simulation as a first case study

 xxxxx 

xx

x


Programming for the real world involves the messiness and complexity of real-world situations, and the need to have a user interface that is, er, ah, um . . . actually usable. Further to this, we often face the challenge for people whose main focus of interest is another subject or problem needing to code in a modern language or to work with coders and understand their challenges. Both of these underscore the need for first proficiency programming. For this, a useful well-proved approach is by instructive case study and tutorial-like discussion. Where, projectile motion with air resistance, drag and lift is valuable in itself and serves as a gateway into flight and rocketry. Historically, it was also one of the first applications of digital computing; in the mid-late 1940's, when some allegedly suggested a global market of perhaps five machines! (I.e., roughly, one per major military power.) As well, it is a window through which we can see into the sort of approach that is needed to analyse, model and solve such realistic problems, then document and report results; that is, a paradigm-illustrating key case study. 

Accordingly, as a model example, let us now ponder the path of a supersonic projectile with air resistance, as is contemplated in Unit P (the gateway programming module):

Another classic case [of the carefully developed user interface and undergirding technical details] is the trigger, bolt, shoulder stock and iron or even telescopic sights of a rifle . . . the complexities of ballistics and building a tack-driver rifle are such that this played a key role in developing modern industries. Indeed, just external ballistics is a gateway to aerodynamics, flight control and yes, rocket science. 

Compare:



 In the case of the classic 0.303 SMLE rifle of WW1 and 2, we can further observe the very carefully curved ramp used to orient the sights to hit the target at ranges from 200 to 2000 yards, with 25-yard fine increments:

British, SMLE Mark III Rifle "Tangent" Rear Sight, with adjustment from < 200 to 2000 yds, in
25-yard marked increments. The muzzle is to the right and the rifle barrel runs under the sight and
the protective wood handguards we can see. Notice, the adjusting slider that "rides" the curved
ramp, and the worm gear for fine adjustments. (On the other side, is a push-button for rapid, rough
range-setting.) Protective ears shield the sighting notch. Early production sights had a L/R
adjusting wheel for the rear sight, to adjust for cross-wind effects. [HT: Handloader Mag., fair use edu. Of course, anything over 800 yards is optimistic and 2000 yards, frankly, is for area targets.]

Here, the curved ramp compensates for the trajectory of the bullet as a projectile facing air resistance and other effects, indeed the rear sight is a simple analogue computer that compensates for the ballistic trajectory. In a vacuum, we can readily show that the trajectory would follow the arc of a parabola, but with air resistance, that is modified by deceleration of the projectile:

A real-world trajectory, with air resistance, cf discussion here. Sight is spelled "site."
(HT WW2 Ballistics notes & an online dictionary. This vid, gives an idea of challenges at 1,000+ yd)

These curves (notice, the ramp on the SMLE sight!) serve us due notice about how fast we get into Mathematical issues. To refresh our memory:


That primes the pump. Now, 


PART 1:
How to begin modelling . . . observations

 We may easily observe a multitude of  trajectories caused by hot lava "bombs" at Sakurajima Volcano, Japan:

Sakurajima erupting Sept 2013, showing high angle ballistic arcs  (and volcanic lightning)
[HT: Volcano Discovery, fair use Education]

We may similarly examine some near-parabolic trajectories, using a water fountain and bowling in Cricket:

 

Now, for a low air resistance case [strictly, a vacuum], the trajectory will be effectively parabolic (as we can see from the water fountain). This is because the horizontal and vertical motions, being perpendicular, are independent. That is, near enough, horizontal speed -- strictly, velocity (speed in a given direction) -- will be steady. Vertical motion, in turn, will be the same as if one threw a ball straight up, then it slows to a stop and falls back down again. In the perfect, no air resistance case, the Math will work out to give a parabolic curve. Here is a demonstration from MIT:




(To get a picture of what is going on, think about a: sitting in a bus moving along a straight road with steady speed [this fixes the horizontal motion vector]. Then, b: toss up a bright green tennis ball and watch it fall back to your lap, as if you were not moving at all. You and the ball are moving with the same horizontal velocity and so, c: to you, you just tossed the ball up and it fell back. But if the bus window was nice and large, d: your friend standing by the road side would see the ball trace out a full parabolic arc. This is, of course, e: a practical demonstration of how perpendicular vectors form a "basis" for vectors in a space, with vector addition/subtraction under the parallelogram law: so, f: vertical and horizontal components of the ball's motion can be isolated -- the bus moves horizontally (x), you toss the ball up and it falls back into your lap (y) -- and separately analysed then put back together. See a first discussions here. 

[Of course, g: this also opens up a gateway into some pretty deep physics: what is absolute rest? It turns out, even in the classical Galilean-Newtonian framework, we cannot distinguish absolute rest from an inertial -- non-accelerated -- frame of reference for motion and position {IFR}. Einstein exploited and extended it, case 1: in the Special Theory of Relativity, the speed of light in a vacuum has the same value c for any IFR, and the laws of physics take the same, simplest form in such a frame. Where, imposing c is constant is based on the Michelson-Morley ether drift null experimental results. BTW, one famous consequence of case 1 is the energy-rest mass relationship e = m*c^2. For case 2, the General Theory of Relativity: acceleration is indistinguishable from gravity, from which we can spin out whole cosmological models for the universe, and of course masses in space warp the spacetime fabric. As a confirming result, in 1919 Eddington observed that during a solar eclipse the apparent position of a star next to the occluded sun shifted from its standard value, due to warping the spacetime fabric by our sun. In effect, too, a black hole tears a hole in that fabric, and more. In short, we are already next door to deep, deep waters just by pondering a ball tossed up and falling back into our lap in a moving bus.])

 Obviously, no air resistance is the simple, idealised case. The more practically important one would include air resistance, shape effects, speed-of-projectile effects on air resistance, wind, spinning of the projectile, latitude and rotation of the earth, direction relative to the West --> East rotation, temperature and pressure of the air, and more. Indeed, extending this analysis leads into study of rockets and aircraft. So, this is a useful topic for studying how computers can be programmed to simulate or model and predict real world behaviour.

A key step to insight is to notice how drag changes with speed from slow speeds, through the trans- sonic zone [the jump] to supersonic motion, for a G7 projectile, as measured (likely, with Doppler Radar that measures velocity directly, from frequency shift of reflected radio waves, taking radar measurements thousands of times per second . . . a revolution in ballistics studies):

Drag for a streamlined standard projectile, the G7 profile, where Drag Coefficient is a measure of
drag resistance and Mach number is ratio of speed to the local speed of sound, which varies
with temperature, pressure, etc, The supersonic part of the curve can be modelled
and is relevant to motion of bullets used for target shooting (HT: Bison Ballistics)

Indeed, Philip Massaro, in his The Big Book of Ballistics, wrote:

the advent of high-speed Doppler radar units and heavy-duty computing power for backend processing has shown us a very different view of [a projectile's ballistic coefficient, BC] . . . We’ve learned that BC is not a [true] constant, but a variable with some basis in velocity and a host of other impacting factors . . . the actual slipperiness (BC) of the projectile changes at varying velocities throughout its flight profile [ --> as in the graph above]. 

Doppler radar can actually be used [with computing] to solid model the bullet in three dimensions throughout its flight. When we model against the actual flight path, we can see the bullet is not in axial profile with its flight direction. When this occurs, the  bullet is presenting to the wind with an inherent amount of yaw, which increases drag and changes the [detailed] outcome of the BC model. The bullet is spinning in either a right- or left-handed rotation . . .  the rotational force of the spin causes the nose of the bullet to precess or climb into that wind. You end up with a bullet not traveling along its intended axial path, but presenting to the air ahead of it a non-conformal profile and adding an amount of drag again . . . 

Also, though it is rather military-like, we may also look at what such a projectile looks like, a shape that also points to aircraft, boat and rocket shapes, to how modern sail-boats can sail by tacking upwind and even hints at why wings have the teardrop-like cross-section shape they do in order to balance lift and drag:

A G7 standard projectile, shaped for superior supersonic performance. Notice the "boat-tail"
and the nose cone. The latter is based on the arc of a circle at ten radii and makes a distinct
angle with the cylindrical, main body following. Just as does the boat-tail.

 Comparing and extending:

 


 We can see too, that the air resistance graph for the G7 projectile has three parts, [i] a roughly steady subsonic part, [iii] a curving supersonic part and between them, [ii] a trans-sonic transition zone. Normally, a G7 projectile is worked with in the supersonic zone. The trans-sonic part, unsurprisingly, tends to disturb accuracy of aim.

This pattern alone, already means there can be no simple fully accurate algebraic solution; also, we are forced to deal with sets of differential equations . . . which, are equations involving rates of change of variables. For simple example, in Newton's Second law, F = m* a, the acceleration a is the rate at which velocity v changes with time, and v in turn is rate of change of displacement, speed in a given direction. So, we have F = m * x''(t). (I here use dashes instead of the more usual dots-on-top for rates of change relative to time.)

As Bison Ballistics notes:

Instead of analytical solutions we must find numerical solutions. That's a fancy way of saying that we can approximate the results of the analytical solution [to the set of equations] for a specific set of numerical inputs. But in doing so, we introduce some error along the way -- you can think of it as sort of like a rounding error. The full physics of the model are accounted for in the equations, but the solution itself has introduced error.

The way numerical solutions work is that you step along the trajectory, calculating in tiny steps as you go. Each step uses the results of the last step [taking care to avoid building up unacceptable accumulated errors] . . . Since computers are doing all the work, we can effortlessly take a lot of steps and get a very accurate solution.

For example, a common technique is to step through time. That means you might calculate the trajectory for every 0.001 seconds of bullet flight. That might be 1,500 separate calculations along the flight path to 1,000 yards. No sweat for a computer. You can also step along distance -- it's often convenient to step every foot or yard through the trajectory. Either way, very low errors can be achieved.

So, let us now outline, first the negligible air resistance case:

 

PART 2:
Projectiles, the "no air resistance" parabolic arc case:

 


 Here, we first notice how projecting horizontally at a height closely resembles the path of a bowled cricket ball, save that as illustrated it is rather steep.  Which, should be no great surprise.

Next, we may see the value of using vectors to separate vertical and horizontal motion. The horizontal motion is steady where there is negligible air resistance so x is proportional to t. Vertical motion faces uniform downward acceleration at g. Vertical displacement therefore follows a quadratic expression in t, and as x is proportional to t, this means the curved path is a parabola, like y = x^2, an ellipse-like curve. 

As, we saw being nearly the case above with the water fountain. 

(Where, the cos and sin terms are Trigonometric ratios due to the inclination of the trajectory at launch, at angle theta-nought to the horizontal. Let us observe:

 


It becomes clear that as the angle of projection rises to the vertical, the horizontal component reduces and the vertical one increases. This affects the steepness of the parabolic arch, and at 45 degrees, for a level ground, range is maximised. At 90 degrees, the projectile goes straight up and down, and at zero it would go along the ground, or if fired from a cliff edge, would follow the descending part of the parabola.)

We could use these functions and equations to write a program that plots the trajectory as a function y of x or in the end y and x of t. 

As one may imagine, air resistance will tend to retard the motion of the projectile at each point along an actual path, and the actual path will be within this ideal trajectory. As we can see sketched above where what would have been a parabola curves downwards more sharply.

Here is a discussion of early developments up to Euler:


 Let us now turn to:

 

PART 3:
Projectiles with air resistance (Pejsa's model):

Arthur Pejsa [= "Pay-sah"] -- a literal rocket scientist working for Honeywell! -- has developed an algebraic representation for projectile drop with distance, on the reasonable assumption that G7-like bullets are typically projected close to horizontally. It reportedly works well for 1,400 - 4,000 foot per second, supersonic velocities. These are a reasonable range for modern rifles etc, note the speed of sound "at sea level — assuming an air temperature of 59 degrees Fahrenheit (15 degrees Celsius) — is 761.2 mph (1,225 km/h)."  Now, too, 1 mph is 5,280 feet/hr; or as there are 3,600 s/hr, 1.467 ft/s. So, this "representative" value for the speed of sound equals 1,116.427 f/s or 340.288 m/s. Of course, for objects moving at speeds well below the speed of sound, such as a baseball or cricket ball or tennis ball, Newton long since showed that a speed square law can be a good model. We will be looking at the Pejsa supersonic case, and it has been convenient to think in terms of modifications/corrections to a square-of-speed model.

 Bison Ballistics notes:

Dr. Arthur Pejsa's famous Pejsa method is a similarly clever method that allows for the equations of motion to be solved by simplifying them - he approximated the drag with some simple equations and came up with a method that is almost as good as what we use today, but that only requires high school math. That's a great achievement, and his method is far simpler than Siacci's [classic result], but it's still not perfect.

This will be an example of how we can use results developed by trusted subject matter experts as a basis for modelling, simulation, systems etc, that are based on programming in relevant languages. Once we have a good result from a reliable source, there is no need to re-invent the wheel. Of course, sometimes, it is a case of having a framework and needing to turn it into a useful program or even application or "app." This case study can help us on both sides of the fence.

For a starting step, Mark Biegert and his Math Encounters has usefully summarised the first stage of Pejsa's calculation -- and pardon naked differential equations; this is for background reference -- no need to "get the vapours" if differential equation notation is unfamiliar:


Eqn 5 in effect says, vertical acceleration y" is g plus a function times vertical velocity y'.

Where, as it contains rates of change, it is a differential equation. 

F/N: Here, y" is d/dt of (dy/dt), often shown as d^2/dt^2 (y). That is the rate of change of (the rate of change of displacement). Acceleration, in short is the rate of change of velocity, which is the rate of change of displacement. Displacement is distance moved relative to a reference point, in a specified direction, i.e. it is a vector as it has size and direction. Using nonstandard analysis, we can then view dy/dt as in effect the ratio of tiny increments in y, dy to the time required for those increments to happen, dt. Here, dy and dt can be taken as infinitesimals, in effect numbers so small relative to 0, that they are smaller than 1/n for any whole number n we can count to. We can identify such a number using Newton's h. Then. 1/h = H, a transfinite hyperreal larger than any n we can count to. The infinitesimal h then allows us to reduce calculus to an extension of algebra. The extended number line involving infinitesimals and transfinites now becomes:

 

. . . and yes, the transfinites just keep on going.

(This approach, as noted above, allows us to treat Calculus as an extension of Algebra. It is just as valid as the limits approach now usually taught, but is more intuitive; it was put on a rigorous footing by Abraham Robinson in the 1960's. BTW, y" and y' are slight modifications of Newton's dots notation for rates, y' = dy/dt.)

 After some fancy mathematical footwork . . . and yes, these are actually first steps along one of the paths towards rocket science . . . we may deduce y, following Pejsa, giving a solution:


This is then converted to customary units, e.g. horizontal distance R is in yards [x = 3*R, in feet as 1 yard is three feet long], speed is in ft/s and projectile drop D in inches; also using a Taylor Series approximation, with G as a simplification and V_0 as initial velocity, or muzzle velocity. (This requires some practical effort (and statistics) to establish.) As to why Pejsa gives drop in inches and range in yards, he is working with people who think in those terms. In turn, we have to take the expert's result and work with that as it is -- warts and all. 

It is helpful to note that at 100 yards, 1 inch subtends about one minute of arc, and that a 1 moa rifle is a pretty accurate gun; obviously, at 1,000 yards 10 inches is 1 minute of arc. Similarly, at 1,000 m, 1 m subtends a milliradian, a mil of arc. Usually for practical purposes a full circle is taken (NATO standard) as being 6,400 mils, where the old Warsaw Pact and German model rounded to 6,000. 

Next, F_0 is a theoretical distance where the speed of the projectile is 1/e of initial value (by which time the projectile would likely be subsonic! Oopsie!); more usefully, Pejsa expressed this decay in terms of distance to lose 1% of its speed. In his New Exact Small Arms Ballistics (Kenwood Publishing, 2008), appendix,  p. 132, Pejsa deduces for a downrange point, the retard or air drag coefficient, F = F_0 - Nx, a linear decline from F_0 = V_0N/a. Accordingly, he notes, p. 16, that F is "the fractional loss in v per foot of travel," so going to the 1% value that does not go outside the valid range of the model by becoming subsonic, F/100, is " . . . the distance in which a projectile 1% of its remaining speed to drag." Where, yes, here we are looking at exponential decay, similar to rise and fall time of Resistance-Capacitance circuits, but can deduce useful simplifying observations and approximations that are good enough for our "practical" purposes. In essence, when a positive or negative rate of change of some variable x is proportional to its value at any given moment, we have exponential decay [if, -] or growth [if, +]. This is the secret of compound interest etc. 

Similarly, g is acceleration due to gravity [32 ft/s per s], A and n are "parameters," values that allow us to fit the expression to a particular projectile, as the worked example to follow will show.

Notice, we are here reducing the above to a relatively simple algebraic expression that we can simply plug values into and read off D for any given R, i.e. our code will have a calculate sqrt-D then square to get D module. 

One trick is to set the start point at say R_0 corresponding to 0.0001 inch or the like, getting away from the notorious divide by zero error problem:


Where F_m is another simplification, tied to F_0 from the original derivations:

Obviously, as R in yards = 1/3 of x (which is in feet), 

F_m (R) = F_0 - 1/4 (n*3R)

and yes, there is a messy mix of units. 

Sources are going to work in terms that are comfortable for them.

So, we start with a test case:

- muzzle velocity (at 0.0001 in to avoid divide by zero errors), here v_0 = 2,900 ft/s
- Scope/sight height above the centre line of the bore, here S = 1.5 in
- zeroed range (the point where the bullet first intersects the line of the sighting device, i.e. factoring in its elevation angle and curved path . . . as,  the line of the rifle bore is slightly elevated), here the second -- falling -- zero point is Z = 166 yd
- Note, the rising zero is called the "near zero" and the one typically used practically is the falling zero point, often at 100 or 200 yards
- the projectile's ballistic coefficient (and so drag effects relative to a G1-like projectile . . . Pejsa actually used a US 0.50 cal M2 Ball round that is closer to the G7), here BC = 0.5 
- an expression for F_0 [theoretical distance for speed to be 1/e of muzzle speed], thence deduced F_m for given distances downrange [F_0 and F_m are in feet, yes x is in feet . . . F_m or more exactly F_m/100 is a measure of further distance downrange to lose just one percent of current speed], where for this case F_0 = 3,576 ft

- a parameter G, G = 41.697 sqrt ft/s
- downrange distance, D is x in ft and R in yards, R = 1/3 x
- a parameter n for how drag reduces with increased speed in the supersonic zone (as the Mach cone angle narrows), here n = 0.5 

 . . . and then deduce projectile drop for points downrange using a model expressed as a formula. 

Where, the intent is to prime our coding partner ChatGPT with information on this case, ask it to use the Pejsa model, then put up Java code to tabulate bullet height (and drop) for R = 1 yard, 51 yards, 101,  151 . . . 601 yards -- to avoid cases where divide by zero might pop up, as a 50 yard first (rising) zero or a 100 or 200 yard falling zero are common, standard practices. Then, we request a spline interpolation and plot a smooth curve. (In actual practice it did this in a few minutes, but of course, it is our responsibility to do a debug reading, and to understand the situation well enough to prompt properly -- which requires ability to design algorithms and to hand code in Java. Of course, real world coding is now in partnership with an AI Assistant; so we might as well begin that way. As, the simple difference in time, labour and initial effectiveness . . . avoiding silly or careless bugs, is already decisive at the outset. Here, initial results -- including finding an exposition of Pejsa's model on the web, took about three minutes and ChatGPT said it was "fun." We are in the AI economic long wave!)

Of course, if one has a need to use more standard metric units, a conversion module can be engaged to work in Pejsa's "customary US" units and return metric results (or as an option, customary units). 

To get D from its root, simply take the square. 

We can summarise the drop-range result, D vs R, from Pejsa's "The Birth of Practical Ballistics," at the Wayback Machine:


The pivotal result now in hand is "merely" algebraic (a huge simplification!), and apparently is often quite good for practical work.  

A typical practical approach, would be to use the summary result in the main discussion of a proposal, progress report or final report, and place the details in an appendix. Refer to the appendix in the main body and table of contents.

A now familiar plot of C_d vs Mach Number,
showing the "sound barrier" transonic drag peak;
however, this is for an aircraft! (Yes, ballistics
is a gateway to studying flight and rocketry.)

McCoy
-- that's a book at the Wayback Machine -- and others, of course give more complex results. Dr Viv gives a fundamental analysis. Hornady's ballistician, in a video, discusses drag for supersonic projectiles, drawing out that the rise in air resistance as such a round slows down is due to how the angle of the shock wave(s) spreads out as excess of speed over the speed of sound reduces. See video of such shock waves here and a discussion of trans-sonic instability here. Yes, this is a case study on how real world complexities and insightful observations intersect. Notice, also, how the Mach Angle m readily gives Mach Number, M, as sin m = 1/M. Where, the ratio of speed v to local speed of sound c, M = v/c and m is half the angle of the "vee" formed by the shock wave (i.e. the angle one arm of the vee makes to the line of flight). Of course, as a flying round goes subsonic the shock wave vanishes and a different, subsonic drag regime emerges, hence the peak and dropoff to the subsonic drag coefficient. 




That's why Pejsa's approach makes a lot of good sense. 

The ballistician (yes, that is a career path) also draws out insights on the fast projectile air resistance expression, especially drag coefficient C_d. And, as the graph to the right shows, the C_d vs Mach Number pattern also applies to aircraft.

 Here is Mach's original shadow photograph of shock waves, 1888; notice, the turbulent wake:


Then, we can see a bullet slowing down as it goes trans-sonic:

Notice how the Mach cone angle opens up as the bullet slows:
in the trans-sonic case, because fluid flow around a body is accelerated,
we see "whiskers" that mark a point of supersonic flow


 

Where, basic drag and lift equations for subsonic flight are:

Where, the terms for the subsonic V-squared "Newtonian" drag expression are:


The Bell X1 in flight. Notice, the chain of shock
diamonds
in the exhaust, a standing wave pattern
(NB: What looks like an oddly shaped p is actually the lower case Greek "R" rho, a symbol for mass per unit volume, i.e. density. The "capital" Rho, just for fun, looks like our P. BTW, the Greek p is pi, which looks like a table end-on as we know from the math of circles. The reference area depends on context, for a blunt object or bullet it is its cross section area as it cuts through the fluid. For a wing, it is the "plan view" area, as wing lift depends on how much wing area there is. The lift coefficient C_l, of course, is similar to drag coefficient. This makes sense as lift is just the sideways component of the same air resistance force that gives drag as the in line component tending to slow down a body moving through the air. There are theoretical expressions for predicting lift and drag, but simulations and wind tunnel testing are standard procedures. In short, if you are interested, ballistics is the gateway to aerodynamics. For example, the Bell X1 rocket aircraft piloted by Chuck Yaeger that first broke the sound barrier was modelled on the US 0.50 caliber bullet, which was known to go supersonic very successfully.)

 In two short videos, the The Efficient Engineer channel further discusses aerodynamic drag and lift, which bridges to flight. In an MIT open course lecture, Tina Srivastava and Philip Greenspun give a good overview of flight. NASA has translated Krasnov et al on Rocket Aerodynamics, which is at Wayback Machine here. Likewise, NASA has a cluster of simulations on aerodynamics topics here.

A "typical" electromechanical calculator (CR)

Of course, in the real world, major global powers have whole departments that operate research laboratories devoted to the study of ballistics with air resistance. Suffice to say, that one reason for the development of the modern digital computer, was to construct firing tables for artillery. This is one way into the study of flight and rocket science. The well known US agency, NASA grew out of earlier bodies that studied such topics. Indeed, standard airfoil shapes in the 1930's and 40's were often given by NACA type. It is worth noting that "computer" used to be a job title for Mathematicians whose job was to carry out such highly technical and typically tedious calculations by hand, or by hand assisted by electro-mechanical calculating machines. 

(As a note, GEM's father, a Statistician and so a human Computer as well as an Economist trained in the late 1950's, could add three columns mentally to any length, transfer the result and keep going. When he first got electronic calculators, he would automatically cross check the result mentally, right up into his eighties. Gen. Erwin Rommel memorised tables of logs and used these to carry out extremely complex calculations in his head. Multiplication and division become addition and subtraction and raising to powers, multiplication. And, much more. We simply point onward to Mathematica, noting that Wolfram has kindly donated an installation of this app -- with a built in programming language -- to the Raspberry Pi. Given pricing, a Raspberry Pi 400 is therefore in effect an educational donation if one wants to use it as a calculation engine.)

This short survey also gives us a sense of how fast the mathematics of a realistic situation compounds, and why approximations often rule the roost. 

Here is a tabulated result, notice, s := s_val is specifying or defining a value:


This is of course suggestive on how a program to tabulate or plot bullet drop could be written, in Java or another relevant language.

As a first step, we tabulate the results above using a Libre Office Calc spreadsheet, picking the XY scatter plot option, displaying points and lines, with a cubic spline function. The result looks rather parabolic, but of course incorporates the Pejsa air resistance model. The bullet climbs to about 2.5 inches above the muzzle-level [- 1.5 inches] at about 100 yards (the system is "zeroed" for Z := 166 yards), then falls to about 47.7 inches below that level at 500 yards:

Now, let us compare a y = - x^2 parabola to see the considerable effect of air resistance:

 

Air resistance causes the projectile to fall off more
steeply than a parabola, as expected, though the eye
would "miss" the difference. Likewise, motion
through the air can lead to lift, hence how wings work


This exercise is, of course, the digital equivalent of plotting points on a sheet of graph paper then using a set of French Curves (or even a flexi-curve or a wooden spline) to fill in a smooth curve.

 It is enough to show that the tabulated results make good sense, especially when we compare an actual parabola. 

Similarly, one could set up a spreadsheet to automate the calculation, and that would be good enough for many tasks. 

However, our aim is to create a program (which is potentially more powerful and flexible than a spreadsheet . . . and is how a spreadsheet is made), so the above helps us see basic tasks for a program for this case: calculate bullet drop for points downrange, tabulate, plot using something like a cubic spline, displaying on a chart. It might also be helpful to print the table. It may help, to know that Libre Office and its sister Open Office, are coded in Java; likely, the charts plotted using Calc are created with Java graphics packages such as JavaFX and/or JFreeChart.

A first step is to hammer out an expression for D(R), substituting for F(m):

D(R) = {[G/V_0] / [1/R -  1/(1/3 * F_0 - 1/4 * nR)]}^2

So, for the case in view -- and yes, to avoid confusion with "x" for a variable it is common to use the asterisk * for multiplication in computing, 

D(R) = {[41.697/2,900]/ [1/R - 1/(1/3 * 3576 - 1/4 * 0.5 * R)]} ^2

D(R) = { 14.6783*10^-3/[1/R - 1/(1,192 - 0.125 R)]}^2

From this, already we see an upper limit to the model, as the denominator goes to zero at a point where, for this specific, particular case we are looking at:

1/R - 1/(1,192 - 0.125 R) = 0, so we rearrange algebraically

R + 0.125 R = 1,192, thus

R = (1,192/1.125) = 1,059.56 yards

However, also, squaring does not preserve sign as -1 * -1 = +1. To detect sign, we need to use a sign-detecting function and store the result in the form -1 for drop below the line of sight, +1 for rise relative to the baseline, as was tabulated above and plotted. Then [sqrt_D] squared can be multiplied by the sign value to get both size and direction of the projectile drop . . . and yes, real numbers and integers have both size and direction so they are technically speaking vectors. 

All of this need to address direction is because, the line of the bore is below the line of the sights and the round is pitched slightly up on firing then peaks and falls away; slightly is important. Illustrating:

(Notice, here, how the trajectory rises to and beyond a first zero point, then falls through a second one. In the tabulated case, 166 yards is actually the second -- falling -- zero point. Also, observe how the line of the sights is above that of the bore. Of course, as we can see from the SMLE 0.303 ramp sight, once a rifle is zeroed, the sight then uses the known trajectory to calibrate aiming for different ranges. This poses a challenge as the formula has a subtraction in the denominator, which means it can go to zero, creating an infinity. In an algorithm it may be necessary to instead work with 1/[sqrt-D) and to use sign detection to pick up and respond to a zero. 

The Pejsa reduction, in short -- and like many other real world models -- gives us a useful model, "warts and all." Accordingly, we must take steps to ensure that we avoid divide by zero errors and also the zero-range point at the muzzle. 

The easiest solution, then, is to recognise that a first zero point at 50 yards is common, or sometimes, 100 yards, and a second zero point for the iron sights or the sighting telescope may be 150 or 200 yards. Accordingly, this model is clearly best used to create a tabulation at a list of specific ranges -- with zero-avoiding offsets -- as we just saw, then we use a spline or similar model to interpolate. Why not, 0 + 0.1 yard, 50 + 0.1 yards,100 + 0,1 yards, etc, out to 500 + 0.1 yards or 1,000 + 0.1 yards (or even + 1 yard)?)

Observe, the SMLE sight again (and yes, 2,000 yards is rather optimistic):









ccccc






 

 

 

 

 







 

 

 

ccc









some effort

UNIT 4 -- A cluster of possible simulations/games

xxxxxx