Weird question but here it is. What are the programming concepts that were "automated" by modern languages? What I mean are the concepts you had to manually do before. Here is an example: I have just read that in C, you manually do garbage collection; with "modern" languages however, the compiler/interpreter/language itself takes care of it. Do you know of any other, or there aren't any more?
Optimizations.
For the longest time, it was necessary to do this by hand. Now most compilers can do it infinitely better than any human ever could.
Note: This is not to say that hand-optimizations aren't still done, as pointed out in the comments. I'm merely saying that a number of optimizations that used to be done by hand are automatic now.
Data collections
Hash tables, linked lists, resizable arrays, etc
All these had to be done by hand before.
If you go back to assembly you could find many more, like the concept of classes, which you could mimic to a certain extent, were quite difficult to achieve... or even having multiple statements in a single line, like saying "int c = 5 + 10 / 20;" is actually many different "instructions" put into a single line.
Pretty much anything you can think of beyond simple assembly (concepts such as scope, inheritance & polymorphism, overloading, "operators" anything beyond your basic assembly are things that have been automated by modern languages, compilers and interpreters.)
Iteration over a collection:
foreach (string item in items)
{
// Do item
}
Database access, look at the ActiveRecord pattern in Ruby.
The evil goto.
First in list, extension method. Facilitates fluent programming
Exceptions, compartmentalization of what is the program trying to do (try block) and what it will do if something fail (catch block), makes for saner programming. Whereas before, you should be always in alert to intersperse error handling in between your program statements
Properties, makes the language very component-centric, very modern. But sadly that would make Java not modern.
Lambda, functions that captures variables. whereas before, we only have function pointer. This also precludes the need for nested function(Pascal has nested function)
Convenient looping on collection, i.e. foreach, whereas before you have to make a design pattern for obj->MoveNext, obj->Eof
goto-less programming using modern construct like break, continue, return. Whereas before, I remember in Turbo Pascal 5, there's no break continue, VB6 has Exit Do/For(analogous to break), but it doesn't have continue
C#-wise, I love the differentiation of
out
andref
, so the compiler can catch programming errors earlierReflection and attributes, making programs/components able to discover each other functionalities, and invoke them during runtime. Whereas in C language before (I don't know in modern C, been a long time not using C), this things are inconceivable
Remote method invocations, like WebServices, Remoting, WCF, RMI. Gone are the days of low-level TCP/IP plumbing for communication between computers
Some languages support Dynamic Typing, like Python! That is one of the best things ever (for certain fields of applications).
Event System
Before you had to implement the Observer Pattern all by yourself. Today ( at least in .NET ) you can simply use "delegates" and "events"
Also built-in functions for sorting(such as bubble sort,quick sort,....). Especially in Python 'containers' are a powerful data structures that in also in other high level and modern programming languages require a couple of lines to implement.You can find many examples of this kind in Python description.
Multithreading
Native support for multithreading in the language (like in java) makes it more "natural" than adding it as an external lib (e.g. posix thread layer in C). It helps in understanding the concept because there are many examples, documentation, and tools available.
dynamic library
dynamic libraries automatically share common code between processes, saving RAM and speed up starting time.
plugins
a very clean and efficient way to extend functionality.
Data Binding. Sure cuts down on wiring to manually shuffle data in and out of UI elements.
Stupidity
That's a thing I've gotten lot of help from modern programming languages. Some programming languages are a mess to start with so you don't need to spend effort to shuffle things around without reason. Good modern libraries enforce stupidity through forcing the programmer inside their framework and writing redundant code. Java especially helps me enormously in stupidity by forcing me inside OOPS box.
Declarations
In single-pass-compiler languages like C and C++, declarations had to precede usage of a function. More modern languages use multi-pass compilers and don't need declarations anymore. Unfortunately, C and C++ were defined in such a poor way that they can't deprecate declarations now that multi-pass compilers are feasible.
Functions.
It used to be that you needed to manually put all the arguments to stack, jump to piece of code where you defined your function, then manually take care of its return values. Now you just write a function!
Type inference
In languages like F# or Haskell, the compiler infers types, making programming task much easier:
Java: float length = ComputeLength(new Vector3f(x,y,z));
F#: let length = ComputeLength(new Vector3f(x,y,z))
Both program are equivalent and statically type. But F# compiler knows for instance that ComputeLength
function returns a float
so it automagically deduces the type of length
, etc..
OS shell Scripting, bash/sh/or even worse batch scripts can to a large extent be replaced with python/perl/ruby(especially for long scripts, less so at least currently for some of the core os stuff).
You can have most of the same ability throw out a few lines of script to glue stuff together while still working in a "real" programming language.
Good String Types make you have to worry less about messing up your string code,
Most Languages other then c and occasionally c++ (depending on how c like they are being) have much nicer strings then c style arrays of char with a '\0' at the end (easier to work with a lot less worry about buffer overflows,ect.). C strings suck.
I probably have not worked with c strings enough to give such a harsh (ok not that harsh but I'd like to be harsher) but after reading this (especially the parts about saner seeming pascal string arrays which used the zeroth element to mark the length of the string), and a bunch of flamewars over which strcpy/strcat is better to use (the older strn* first security enhancement efforts, the openbsd strl*, or the microsoft str*_s) I just have come to really dislike them.
Programming itself
With some modern IDE (e.g. Xcode/Interface Builder) a text editor or an address book is just a couple of clicks away.
Pattern matching and match expressions
In modern languages you can use pattern matching
which is more powerful than a switch
statement, imbricated if
statements of ternary
operations:
E.g. this F# expression returns a string depending the value of myList:
match myList with
| [] -> "empty list"
| 2::3::tl -> "list starts with elements 2 and 3"
| _ -> "other kind of list"
in C# you would have to write such equivalent expression that is less readable/maintanable:
(myList.Count == 0) ? "empty list" :
(myList[0] == 2 && myList[1] == 3 ? "list starts with elements 2 and 3" :
"other kind of list")
A whole bunch of the Design Patterns. Many of the design patterns, such as Observer (as KroaX mentioned), Command, Strategy, etc. exist to model first-class functions, and so many more languages have begun to support them natively. Some of the patterns related to other concepts, such as Lock and Iterator, have also been built into languages.
Context Switching.
Most modern programming languages use the native threading model instead of cooperative threads. Cooperative threads had to actively yield control to let the next thread work, with native threads this is handled by the operating system.
As Example (pseudo code):
volatile bool run = true;
void thread1()
{
while(run)
{
doHeavyWork();
yield();
}
}
void thread2()
{
run = false;
}
On a cooperative system thread2 would never run without the yield() in the while loop.
Variable Typing
Ruby, Python and AS will let you declare variables without a type if that's what you want. Let me worry about whether this particular object's implementation of Print() is the right one, is what I say.
Auto Type Conversion.
This is something that I don`t even realize that language is doing to me, except when I got errors for wrong type conversion.
So, in modern languages you can:
Dim Test as integer = "12"
and everthing should work fine...
Try to do something like that in a C compiler for embedded programming for example. You have to manually convert all type conversions!!! That is a lot of work.
Memory management, anybody? I know it's more efficient to allocate and deallocate your own memory explicitly, but it also leads to Buffer Overruns when it's not done correctly, and it's so time consuming - a number of modern languages will allocate and garbage collect automatically.