Some abstractions around programming: Difference between revisions

From Helpful
Jump to navigation Jump to search
Line 534: Line 534:




=Scope=
=Scope and namespaces=
 
<!--
 
If you think at machine code level, you just have a lot of memory you could write and read.
It's your job to think about what bits of code touches it when, and whether that makes sense.
 
You have to do absolutely everything yourself, you ''can'', and early programming
but you can imagine people started adding abstractions that made life simpler on them
 
 
For example, the function call is probably the singular most useful tool.
Aside from the purely functional part of giving a useful fragment of code a name so that it can be easily reused,
it also turns out to be ''really convenient'' if you can also give it its own little scratch pad that won't interact with the rest.
...more specifically, if the language you work in ensures that variable names defined in the function implies
every time you call it, that variable is usable only within that function  (...we can worry about where that memory comes from elsewhere. We ''have to'', but that also becomes a separate topic).
 
That means anything outside can't accidentally interfere with it (by accidentally using a variable name that someone else happened to use elsewhere.
 
This compartmentalization makes both names less messy, and makes memory access less messy.
 
That function's '''local scope''' is dis
 
Yes, you have to deal with the fact a function might now refer to both things in local scope and in global scope,
and that even introduces some new problems, but generally the benefit outweighs the cost (particularly if you set some extra rules for yourself).
 
Yes, you can typically break the abstraction that is scoping, but only intentionally.
 
 
 
 
Similarly, once you add a lot of different functions, you start having more and more names,
and they will at some point conflict.
 
''Variable'' names may have the benefit of often being local to functions,
but most ''function'' names are just on a heap of ''everything that exists that you can draw on''
 
 
When you choose to (or have to) put names within a specific namespace,
you can only get to those names by explicitly poking into the namespace.
 
This is often done to avoid ambiguity, particularly if you use names that other names
 
 
 
Namespacing is a general term.
 
Some language use the term as a specific concept, e.g. in C++ {{inlinecode|namespace}} is a keyword, a named block with names inside.
Other languages do most of their name organization in other ways. For example, python organizes its code mostly though packages and modules.
: namespaces are still a thing, but it's more about "built-ins come from a special-cased namespace", "your own imports go into a program-specific namespace", and "actually that also happens at function definition level"  https://realpython.com/python-namespaces-scope/#namespaces-in-python
 
...which runs a little into scoping
 
-->






[[Category:Progamming]]
[[Category:Progamming]]

Revision as of 12:21, 13 September 2023

Some fragmented programming-related notes, not meant as introduction or tutorial

Data: Numbers in computers ·· Computer dates and times ·· Data structures

Wider abstractions: Programming language typology and glossary · Generics and templating ·· Some abstractions around programming · · Computational complexity theory notes · Synchronous, asynchronous · First-class citizen

Syntaxy abstractions: Constness · Memory aliasing · Binding, assignment, and such · Closures · Context manager · Garbage collection

Sharing stuff: Communicated state and calls · Locking, data versioning, concurrency, and larger-scale computing notes

Language specific: Python notes ·· C and C++ notes · Compiling and linking ·· Lua notes

Teams and products: Programming in teams, working on larger systems, keeping code healthy · Benchmarking, performance testing, load testing, stress testing, etc. · Maintainability

More applied notes: Optimized number crunching · File polling, event notification · Webdev · GUI toolkit notes

Mechanics of duct taping software together: Automation, remote management, configuration management · Build tool notes · Installers



Mathy concepts, state

Invariants

In math

In more practical engineering

In programming

Class invariant

Memoization

In programming, a memo function is a function that remembers the output for a specific set of input parameters it has previously processed, and can answer from that memory rather than from calculation.

Using this as a speed/memory optimization tradeoff is called memoization.


It becomes effective when the duplicated calculation is nontrivial to calculate and/or when the a function is often called with the same input.


A memo function should not have any intentional side effects, or (in general) depend on any external state.


In some cases, memoization is something from the language/syntax itself, particularly in more functional languages (e.g. haskell), but in procedural language it's often done with a more explicit cache, which requires some management, e.g. to keep the cache of answers in check, and possibly even be smart about retaining entries that are requested more than others.

Side effects

This article/section is a stub — some half-sorted notes, not necessarily checked, not necessarily correct. Feel free to ignore, or tell me about it.

In computing, a side effect tends to mean altering some state outside the environment in consideration.


You may see this most often in programming, where e.g.

  • a function that can only refer to its own local variables can never have side effects (...on other code) - (see also pure function)
  • a function that alters global state may easily have effect on other runs of that same function -- or on anything else that happens to rely on it.
  • a function that shares state with others by design
alters shared state tends to be more intentional, done with



More practically, you usually talk about side effects to talk about when you share state, particularly when you unintentionally share state, and particularly when this can lead to issues like race conditions.


...and also when intropducting the abstractions we introduce to avoid such issues.


Such abstractions include

clearer/singular owners of state,
exclusive access to state,
or e.g. concurrent data structures, which exist to tame such issues.


Side effects are not necessarily negative, in that if there is an implicit/explicit contract pointing out how to deal with them. For example, one approach to concurrent data structures exist to have things work predictably even in the presence of side effects.



https://en.wikipedia.org/wiki/Side_effect_(computer_science)

Idempotency

This article/section is a stub — some half-sorted notes, not necessarily checked, not necessarily correct. Feel free to ignore, or tell me about it.

In most contexts, the point of an idempotent operation is that it has no additional effect if it is done more than once.


In general, in machines

For a tactile example, consider an industrial machine has an separate 'on' and a separate 'off' button.

Regardless of the state before, if you press the 'on' button, it is going to be on afterwards
Regardless of the state before, if you press the 'off' button, it is going to be off afterwards
...also regardless of how often you press that same button afterwards.


In comparison, the power button on most computers toggles (and is only a request to change - unless held for 4 seconds as per ATX specs)

...so you won't know entirely for sure about its state afterwards
so it's not idempotent.
(the fact that that's because action depends on the current state just happens to be the main reason, not a defining part of this non-idempotency)


Stoplight crosswalk buttons are idempotent (with few exceptions)

in that you can press them more than once, but it'll just stay in 'requested' mode until the system acts on it.
(and sometimes nullipotent, meaning the light will schedule you regardless of whether you pressed, and it's there just to make you feel in control)
  • elevator call and floor buttons are idempotent (with few exceptions)
...even if people like to hold on to their magical thinking about special modes that make it go faster


In math, in computing


In math and computing, you're saying the output doesn't change if called more than once (with the same input parameters).

For example

  • anything that makes no changes
e.g. HTTP GET, HEAD, OPTIONS, TRACE
though people do abuse GET (e.g. allowing sets from GET requests, not just POST, is moderately common)
  • adding or removing an item to a set
e.g. HTTP DELETE
  • various string operations, e.g. uppercasing a string

...and may more than we usually don't name specifically.


Such a property happens to be useful, in design, and in talking about design, in particular APIs, because you're typically modeling what should happen on the other end, and are usually not inspecting or policing every step.

Say, it's really useful to know that if an identical operation is sent to a server several times, it leaves the server in the same intended state.

Around updating state, this can e.g. simplify complex state management to 'just retry until is says OK'.


For the HTTP examples,

It's just defined that way so that HTTP clients can assume certain things.
it's not that you can't break that, by mistake or even by choice. In particular GET is sometimes not idempotent in practice.



Around parallelism, this relates to things like reentrancy



Scope and namespaces