POINTERS ARE FOREVER
|
|
Be the pointers with you: in fact you use them every day!
|
Alone in the dusk shadowboxing a shade that stings back: this is the supernatural profiling that becomes whoever masters pointers. For it's prestigious: prestigious as being acquainted with the trust of the notoriously avaricious shadows; since either you a fool or by hovering and hovering you attained those speculative thresholds where things slowly fade away to offer and reveal the hue they since ever shared with the eternal spring, breathing silently and doggedly bouncing back where only angels dare to tread and only divine nostrils would dare to inhale. Dangerous: dangerous like any subtlety can be when you're coping with the esoterica and you do not show respect or awe enough. Unsubstantial like a pointer, fainting like a Brahms' ballade approaching its ending accord, alike a background echoing soundtrack of a closing Chopin's arpeggio reverberating by the bystanders and vanishing in the thin air of the chambers. Like a pointer.
So you kept wondering all along this time what a pointer is. I know how to explain this to you. Just trust me, grab my hand, and follow me wherever I lead you.
- You now open a blank text file on your desktop or if none you create it (on windows systems you know: just right click your mouse on an empty sector of your desktop and from the appearing drop down menu choose new --> text file). Once created you can give to such newly created file a name or leave it nameless, no matter. Left click on an empty sector of the desktop once, in order to allow the definitive storing of such new file. Trivial stuff so far.
- You now put your mouse arrow on it, highlight it, you then right click again and from the same drop down menu you this time choose: copy: yes, you just store in your computer's temporary memory a copy of this newly empty (namely text less) generated text file.
- You now open this very same document by double clicking on it. Do as you are told.
- You now write in it: "Hallo world", you save and close it.
- You do have closed and saved it, don't you...?
- You now open another, different folder, no matter which one: maybe it's your My Documents folder.
- You now right click in an empty corner of that folder, and from the drop down menu that would once again appear you this time select: paste.
Obviously, the document that you had previously cached
as the currently copied document, would now be copied in this latest folder.
- You now do open this latest document.
- Behold and surprise: you'd expect it being a blank document, correct? In fact when you copied it you had not written anything in it yet. But with your extreme puzzlement what you have now before your eyes is not an empty document but: "Hallo World".
Scratching your head you wonder how darn comes, for you are positive you copied it before writing anything onto it. This is what happened: when you "copied" the file, you did not copy the actual file but a mere reference to its location, so whatever change the original file would have possibly underwent would be reflected in the pasted document as well: in fact if you are storing not the actual file but the address its original template is located at, whatever happens to the original template location would affect its hovering copy, for it isn't but a reference to such location. Such process, namely sneakily storing not the actual object but its mere location, that is a pointer indeed. Why doing this, you may wonder? To save memory: when you stock in the memory an object, it's at first stocked as a mere record of its original location instead of letting a possibly 100 megabytes object copy linger in no man's land, unless by giving the eventual command (paste) you implicitly (and arguably clue less) issue the order to finally produce the actual copy. So at first you just have a pointer: namely a finger that points (references) to an hard disk memory location, and only after you deliver the paste command the actual (and finally fully
independent of the original) copy gets relinquished and bequeaths all the original object's properties (such as the printed and previously saved text) the original object (file) still exhibited one millisecond before such copy was finally released and disentangled from its parent template: a process, this latest one, known as de-referencing (or, more correctly and to skip a valid technical objection, a process which by dereferencing sets up the requirements for the production of an independent copy of the referenced object).
So take a breath, for you just got once and for all what a pointer (as well as a reference) is. Which is a good pledge fulfillment to start with, isn't it?
POINTERS AS FUNCTIONS
|
|
Pointers are a special type of function.
|
When given two abstract objects as, say, A and B, you say that A is a function of B, you thencefore mean to imply that when something (not defined yet for the most general definition of a function is unspecific as far as the details are concerned, and simply stresses the existence of some level of interconnectivity) in B gets changed or modified, it produces some proportional changes and/or modifications in A as well: you can syntactically write it as:
A=f(B)which means, precisely: A is function(...al) of B. As we have stated, this way of expressing a functional type relationship between two given objects, is rather laconic: it just says a relationship of some kind exists, but none the less reveals nothing on its degree or conditions upon which such relationship takes hold and proves its power. It discreetly limits itself to hinting that such a connection, somewhere, subsists.
I am probably going to puzzle you again if I'm to say to you, out of orthodoxy to some degree, that the first and simplest kind of function like relationship where finally something on the nature of its texture is revealed, is the assignment itself:
A=B
whereas treating an assignment like that as a function instance is undoubtedly original, and none the less quite exact: in fact it can legitimately been conceived/perceived as a functional relationship where object A is functional to object B as far as... everything is concerned. Therefore whatever change in B would be fully and integrally mirrored on A: assignment as a function.
Now, it's two completely different lots, whether you're going to write A=B as a way of stating that such integral functional relationship is instituted ( A=4) or is predicated ( A=B): period, big pause, ponder words (with an eye to the examples...).
In the former case you institute the functional assignment like relationship, in the sense that you enact it, as a demiurge; in the latter case you say that such a relationship between object A and object B has been declared but that, at least to this very same moment, has not been enacted yet for nothing in B has changed yet such that it could be mirrored in A: were it going to be changed, it would.
Such difference survives in programming and scripting as well (whereas programming differs by scripting in the sense that programming is normally heavily data typed language but scripting is not - and for more on this just read on).
If you'd assign to a variable a number like 4 ( A=4) the integral functional relationship (as we called it) would persist throughout whatever subsequent assignment A would undergo, with the characteristic that if A would survive, its binomial partner number 4 would not: for if I first say that:
A=4
and then I say that:
A=11
surely A once carries a fully functional identity with 4 and later on it carries a fully functional identity with number 11, and in both cases although the value held by A changed, none the less A retained an objective personal persistency which, just switching value, survived to the process: it can still be addressed as A and would respond to a call: something perseverates, for A is an object and can transcend its values' fate. But in that very same process number 4 got irremediably lost: it was " just a number" namely had no global or perennial identity that would guarantee a surviving of "personal" relics or contours.
Such objects in programming are called: primitive data types, and by and large they are: - bare numbers
- strings
Languages can define more differentiate primitive data types by dancing around this scheme, such as for instance integer primitive numerical data type and floating primitive numerical data type, whereas the former are traditional integer numbers (such as 10) and the latter numbers with a floating fragment (such as 10.50 or even 10.00); but nothing in this specific embodiment of the same situation changes the underlying fact that there are two basic primitive data types on the whole: Numbers and Strings, and that their common heritage is that nothing is more volatile than their existences.
Whatever holds a primitive data type as its value, is unfit to become a pointer.
Why?
Because primitive data type can't exhibit a persisting remains of themselves, so there would be nothing to point at in the first place, and checkmate at the first move: as soon as they change, they change so much that you can't address anything of what they where before any longer: they have no past, no story, no track record, and certainly an uncertain future. You can't point what can't persist, and although you can drink pepsi from within a coke can, you can drink no pepsi and no coke at all without a can that would outlast its contents.
I deem you have got it: conversely, whatever is neither a number not a string is suitable to be pointed at. But what is such a thing which is neither a number nor a string: a chimera? It is exactly what I said it is: whatever is neither a number nor a string: example:
B= new Array(1,2,3)
B is now an array, which isn't either a number or a string: correct?
Therefore B can be "pointed" at.
If:
B= new Array(1,2,3)
and:
A=B
now A is not simply equal to new Array(1,2,3): it is more precisely equal to B itself, which is an even stronger statement with dramatically deeper ( and more insidious) involvements than suspected: in fact this means that if B undergoes a change such as B[0]=5 and therefore B is now an array like: Array(5,2,3), then its change would be diligently replied replicated and mirrored by A as well, therefore proving a complete lack of independence of A from B. And such lack of independence is so thorough, that it can be furthermore proved by the fact that if I change something in A by saying, for instance, A[0]=14 and therefore A should be Array(14,2,3), well now even B is holding the value Array(14,2,3): the two objects are one, are the same thing, no matter what's their value (for neither is primitive data type). Therefore pointers bring about a bidirectional function(al) identity.
All of this happens because by merely stating that A=B, and provided B being initialized as an object and not as a primitive data type holder, what we instituted was not an assignment of primitive data type, but a pointer function(al) relationship: and if something changes in object B (analogously to the situation where something changed in your example file we produced at the beginning of this treatise), it would be faithfully reproduced in A as well, and therefore vice-versa too (it's like Kepler's law: « the gravitational attraction of two bodies is directly proportional [or... functional! - my note] to the product of their masses and inversely proportional to the square of their distances»: the square, the two planets entertain bidirectional ratios!): and this happens because what has been "assigned" to A is not a value, but a memory location (of another object) whose vicissitudes can exhibit a survival rate to their very same alterations: in fact if single primitive data types held by the array are changed and therefore the previous primitive data held by the array branches get forever lost, none the less the array trunk is still owned by another holder, B itself, which guarantees, with its roots, the persistence of the memory location it was planted in: it can thus be pointed at, and it is; A=B can so really be and intently mean... A=B !
All this requires special care and attention to the case you have a variable which holds primitive data type, and you set a second variable as equal to such former variable:
B=10;
A=B;
Since B carries primitive data type (number 10), it is unfit to be pointed at: therefore A=B doesn't implement a pointer. If you change the value held by B, such change will not be reflected in A:
B=10;
A=B;
B=280;
Primitive data types set as the unique value of a variable, make the variable itself unavailable for being pointed at.
I know you may have two questions.
First: "but in my file I wrote primitive data type: a string, so it should have not been pointed at".
No, you didn't. What you did is to copy an object (of the file type!) whose property "text" (a property out of many others a file object possesses!) you set to "Hallo World": therefore whatever change the property department would endure, the overall file object could still persist encompassing it all, and therefore being fit to enforce/produce a pointer like functional relationship.
You may argue as well: why it gets pointed by default, what if in my scripts I don't want it to be pointed? You hit to the heart of the matter: pointers in some languages can be much more of an hassle than a blessing, and other times (if duly managed) a relentless spring of unleashed authentic power.
When a pointer is treated by a language as something about which you can decide if it has to be a pointer or not, we talk of a reference instead of talking of a pointer: you can reference, you can dereference (remember?) and consequently get rid of the pointer function liaison; some programming languages let you choose, at least in the sense they provide you, in the worst case, with pointers by default and references by choice as well.
I don't know C, but I can tell you that in Perl you don't have pointers by default at all: whatever assignment such as A=B would produce two independent objects already, unless you overtly express by the agency of the proper syntax you want a pointer like relationship being implemented among them.
Actually, this is true as far as an example like ours is concerned: assigning an array Object type to a second variable: this in Perl positively produces no pointer: but arguably there can be other circumstances (like OOP approaches) where such a rule couldn't be relied upon so safely: whichever the case, what really matters is that you're by now developing a keen awareness of what pointers are, and a doubtless ability to detect them in case they'd cross your road by producing strange outcomes in your scripts.
Also, in Perl dereferencing doesn't produce an independent object yet and in itself: but an assignment A=X whose second term (X) is the dereferencing of a variable (say B) previously set as X's referenced object, would indeed bestow the first (A) term of the assignment with an independent copy of the object (B) originally referred (pointed) by X: A=X. Thus, speaking of actual direct referencing/dereferencing capabilities, makes sound sense, as well as differentiating between pointers and references does, especially when pointers do not prowl around by default.
Other languages do not provide you with referencing capabilities at all, and therefore they hand over no choice at all: which does not mean they have no pointers and therefore can implement no pointer aware politics, or cannot cross into unexpected (as well as allegedly mysterious) pointer generated obstinacies and unwanted obsolete data persistency (or, more correctly and likely, impossibility to make "older" data stored in A resist and persist to changes presumptively meant to affect only B - and vice versa).
I said that some languages that let you deal with references are, quite remarkably, C++ and Perl.
Conversely, Java and JavaScript have no referencing power (and therefore are at times and quite wrongly argued as having no pointers, via a surreptitious assumption a pointer is an interchangeable term, or maybe even an equivalent, of/for a reference given their common original playground) but they have only these subtle, implicit, default bundled pointers (which I at times call: stark pointers): and no doubt that if we were to schedule a major leap forward for javaScript it wouldn't be by adding exception throwing potentiality to it, but prior to all... referencing and dereferencing capacities.
I even dare propose the following syntax (you can skip this box if you prefer!):
A Modest Proposal: javaScript++ and a normalized reference approach? |
(!)myVariable=anotherVariable
(+)myVariable=anotherVariable
anotherVariable=(-)myVariable
(+)anotherVariable=(-)myVariable
anotherVariable=(-+)myVariable
(-)myVariable.aProperty=10;
(--)myVariable
myVariable=(-)myVariable
function foofoo(){
static myVar=1;
myVar++
}
function foofoo(foo1='defaultValue', foo2=1){ //...
function bigfoo(static foo1=(-)){ //... }
|
In a language that offers no referencing capabilities, you have only 3 ways to compel a pointer to quit its pointer nature:
- You go on unfolding all the structure of one of the two objects until you reach a branch/property of the reeling object whose eventual value is primitive data type:
if you assign such latest value to the other object, it will be assigned not like a pointer but like the actual independent value, for it's primitive data type, and no pointer like pattern would be meddling in the way any longer: example of a loop spreading an Array data type held as the value of our example variable named B, in order to gather the primitive data type packed in the array's entries:
A= new Array();
B= new Array(1,2,3);
for(var i=0; i<B.length; i++){
A.length++
A[A.length-1]=B[i];
}
Since you have assigned to A not B itself but its unfolded eventual values which we know were primitive data types, now A is an Array object like B, but completely independent of B and if B undergoes changes, none of them would be knocking at A's door.
At times languages that do not provide referencing and dereferencing powers provide built in methods that already produce copies of the fore said type, and therefore inferentially untie whatever pointer could be lurking around: such a method in javaScript is, to cite one, Array.slice() :
A=B.slice(0) yields two different objects and no pointers.
- By exploiting the lifespan scope of the variable.
All variables, as you know, have a "lifespan" which can be either global (namely they last and can be utilized and addressed -set and read both- as long as the loaded document is in the browser's memory) or which can be limited to the block (basically, the curly brackets set) within which the variable has been initialized first: for instance a variable which has been created in within a function -or within a loop- would not exist (and consequently could not be set or read) any longer after the function has concluded its tasks -or after the loop has concluded its iteration- at each invocation of it, and could therefore be manipulated only within the scope demarcated by the curly brackets wrapping it.
In JavaScript a variable whose lifespan must be limited to a block, must not only be created for the first time in within that very same block (and not outside of it, or its scope would be broader!) in order to last only as long as such block gets executed or involved in a task, but they must also be initialized as such by prepoining to each of them the keyword var too. Forgetting doing so would, in javaScript, initialize in within the block a variable whose scope would actually be... global!
Therefore a variable which, for instance (and no matter how silly an example it may be), has been created first in within a loop as an object:
for(var i=0; i< 10; i++){
var B= new Array(i);
}
could be invoked and used only in within such block (I repeat: in within that specific curly brackets set: for curly brackets are the item which differentiates and delimits each script block by subtending its starting and closing boundaries). Therefore, in within that block another variable named A (and previously initialized outside that block, and namely whose lifespan outlives the B's one) can licitly be set as equal to B, instance:
A=0;
for(var i=0; i< 10; i++){
var B= new Array(i);
A=B;
}
In within such loop block, the bond which characterizes the equality we created A=B is still of the reference type we described so far. But as soon as
we exit the loop, a call to B would obviously yield undefined or even an error for B doesn't exists anymore out of the loop and thence can't be set or read; but, conversely, a call to A can still be performed successfully out of the loop: not only A could still be read (and set, if necessary), but A would also still retain the last value/object B held in the last instant of its lifetime (that is: A's value does not get nullified by the termination of B's lifetime, "despite" the pointer like relationship).
This happens as a consequence of what we debated in the previous point: for nothing expresses more radical a change of data type in a variable's fluctuations than causing it to die and lose whatever data type (such variable, more specifically, gets the so called null data type).
Upon such critical an event, every variable entrusts to its pointers its original object as an independent object (but this only as soon as you're out of the block, for as long as you're within it, each adjustment of B -provided as usual B is not holding primitive data type- would affect A as well).
The most critical thing you do have to keep in mind when dealing with potential pointers in these latest cases (which is also the case, namely, of languages that do have implicit pointers -say stark pointers?- but lend to you no explicit referencing powers)
is that if you assigned more than one variable as being equal to B (to go on with our example) such as for instance:
A=0;
A2=0;
for(var i=0; i< 10; i++){
var B= new Array(i);
A=B;
A2=B;
}
then both A and A2 would surely inherit B's value as an independent object (independent of B, for B doesn't exist any longer) and would not be annihilated along with B (would not carry null values as a consequence of the fact B now
carries such a "value", that is): but between A and A2 would still persist a pointer like relationship such that if I change something (like an entry value in the array, to follow our example) in A, such change would be replicated in... A2 - and vice versa.
Something to keep in mind, in all likelihood!
This latest developement was probably unexpected a fact, that anyway shows to you that even the variable named A is actually still a... pointer, but "he" doesn't have any more B as a competitor to that memory location: what gets bequeathed are memory locations, the memory positions, and if nothing refers any longer to such locations, only then such sockets can disappear forever from the memory session storage (which is at times called garbage collection, a task that javaScript and Java do on their own without the scripter having to look after it, whereas other languages like C seem to require the programmer doing it, or the memory location would persist being allocated with the digital object even if nothing points at it any longer - an annoynace indeed, if that memory location is eating up, say, 10 Megabytes that clearly nobody is going to use any more).
Actually, you can now see in languages everything isn't but a pointer, beyond the appearances and above the surface there are memory locations which hover; even a mere assignment isn't therefore but a pointer to such a memory sector, which significantly consolidates what I've been telling you about assignements as functions.
- You reinitialize again the previously referenced object, and you reinitialize it either as a new instance of an object by keyword new, or you simply reinitialize it by its roots, as if you were eradicating what it was before: say something like:
B= new Array(1,2,3) A=B;
B=55 //A retains (1,2,3) and NOT 55 !
or, probably more significantly:
B=new Array(4,5,6); //A retains (1,2,3) not (4,5,6)
these would be such radical moves for they all imply either a switching in the data types (from array object to number) or a change by the foundations, that would anyway and consequently force A, originally pointing to B in our example, to have nothing more to point at at that given memory location: in fact the space allocated for that data type has been basically changed to the degree it doesn't exist any longer at that hard-disk location, and therefore A simply retains the last object B embodied, as a film impression of it, or as its legacy: and since B as it was doesn't exist any longer to its very same roots, for it become another data type and therefore required a new, different slot of memory, also the pointer that was swinging in between doesn't live on for it has nothing left or allotted in the destination it was used to rebound against. Reinitializing an object completely anew, or changing its data type, causes the computer to allocate a new (and therefore different) memory address for the new data type or for the brand new generated full object, and frees and dislodges all its pointers making their left polarity (say A) inherit, as an independent vestige and a last token, whatever B previously held. Oppositely, as we have been repeating so far, simply changing an object property's value, namely without changing what such object (B as a whole) was by its bases, would not uproot a pointer binomial relationship at all; on the contrary, it would show all its strength by reflecting the changes of that property's value in both variables.
| A note on Leonardo |
You may have noticed that in this perspective what is on the right side of the assignment is the real ruler, despite our habit would persuade us into considering what is on the left side as the leader. Therefore an expression like A=B should put the stress on the B, not on the A.
It's like reading from right to left, a practice that I encourage you to keep in mind when perusing code: first read what must be executed, and later upon which conditions: what has to be executed is the why, so against all odds, it's more explicative that the conditional statement that introduces it.
After all, also Leonardo da Vinci was an engineer that wrote from right to left (yes, he wrote backward), and was not a worthless engineer: the image you see here, is an excerpt of one of his projects, and as you may notice, yes: that's a Chinook, for it's a chopper. Do you know when he projected that? I will tell you: on 1515.
It is probably significant also that a man like Bill Gates purchased the Atlantic Code, probably Leonardo's most remarkable achievement, so remarkable a digest of human genius that whatever Almagest would turn aghast and pale by comparison: even stranger therefore, given our context, that the writings of a man one of whose funny things was that he grew used to write from right to left, were also the writings that the man who led a significant amount of the contemporary digital revolution felt such an elective affinity with, that he bought some. |
FUNCTIONS AND POINTERS [ more technical ] |
You know that programming functions (at times called subroutines or methods) may accept parameters called arguments: that is, since the standard shape of a function is: function myFunc(){/*code here*/}, all that may be in between the round brackets is called argument and is a way to introduce inside the function values that had been previously assembled/generated in the environment outside the function itself: function myFunc(anArgument, another){/*do stuff with arguments too*/}
Actually, you should consider the arguments just like variables, whose assignment by the symbol (A=300) is not made directly but implicitly upon passing them to the function (the following snippet makes something silly again, for it's just an example: it changes the third entry of an array - 0,1,2):
A=new Array(1,2,3,4);
function foo(anArgument){ anArgument[2]="changed it!" }
foo(A)
So, as you may have noticed, the argument called anArgument isn't but a variable name whose scope can consequently and accordingly exist only within the boundaries of the function (namely as long as the function is called and gets executed, and all such arguments vanish in thin air as soon as the function stops being executed for it performed all the code that was inscribed and prescribed in between its curly bracket set): the value of such variable name gets assigned (xy) in an implicit way when ,by calling the function, we also insert in the location meant for the argument name, an actual variable holding actual data produced somewhere else in the script.
So yeah, you got it: a pointer like relationship might be bushwhacking, for the value of a variable is going to be passed as the value of another... variable!
Well, in fact and consistently with this treatise, arguments in javaScript do behave as pointers they are passing as their value an Object which is not primitve data type!
A=new Array(1,2,3,4);
function foo(arg){
arg[2]=155;
};
foo(A); alert(A);
Such snippet would prove to you that the variable named A has been affected, and therefore there was enacted a pointer like relationship, for A did not hold primitive data type. Obviously, to avoid this (if you want to avoid this) your codes inside the function body must put in action some of the tactics described above, most likely #1.
This behaviour should make you reflect and ponder more thoroughly on the consequences conveyed by #2: we said there you can exploit the scope of a variable to get rid of a pointer, but rest warned that whatever thing such a local scoped variable might do to another variable as long as the former's lifespan keeps running, would permanently affect the latter. Makes sense, correct?
Last but not least, there are languages like PHP which have pointers, by and large, only if you openly declare by the proper syntax to show you do want a pointer like relationship being instituted between the two variables: Such languages require that you establish the argument meant to be a reference as an openly declared reference in your function definition itself, or such a passage of arguments may not produce the automatic pointer.
This should stress even further how things may change as far as different languages are concerned depending upon the fact pointers are allowed or not to be overtly referenced: whenever (also by the agency of this document, maybe) you suspect you might be going to face a pointer (for you're certainly developing a cutting edge knowledge and cognizance of them and of their favourite resorts and recreational compounds...), you should first check with a test (a code snippet conceived by you just for such a puropse, that is) what your language behavior is: Robert Frost would probably call it being acquainted with the night, but you have to get acquainted with your own language, so understanding pointers doesn't necessarily mean you know since the beginning what a language does with pointers, but it does mean you know when your language could be suspected of being about to establish (or not to establish) a wanted/unwanted pointer between two objects, because you suspect a pointer-like linkage might be in the offings, and so by a simple you can harvest one of the deepest and more meaningful knowledge (and mastering) of your preferred scripting pet. PHP uses an & symbol to force in a pointer even on primitive data types, so:
function foo(anArgument){/*stuff here*/}
would imply the argument will be automatically a pointer to the original which gets passed, no matter what data type the passed argument holds.
Please, let me repeat that what you have most significantly to note here, is that by allowing overt referencing by a specified syntax, a language allows to point even primitive data type (never, never pointed by default: but if you have a syntax which can reference, then obviously even primitive data get suitable for being referenced).
The second thing you most remarkably have to take note of, is that without the & symbol, PHP might not establish a pointer like relationship inside the function even if the passed argument is an object (test it with an array object if you prefer): so a language which provides a specific syntax for pointers does not allow (at least to date, for as I said I'd favor an approach where both stark pointer and references might coexist and I hope one day a javaScript++ may live) the setting up of a pointer if you do not explicitly require it by the appropriate syntax.
Since such argument pointer that we just called anArgument would evidently disappear as soon as the function exits, if inside the function body you want to make some other external object be a pointer to the object that you passed as an argument, you have to do this before the argument lifespan expires; a language like PHP which has not stark pointers, requires you to point it again or what would be passed would be the value but no pointer like relationship would subsist with the originals: pseudo PHP code:
anExternalVar=10;
anotherExternalVar=50;
function foo(anArgument){
anExternalVar=anArgument;
}
foo(anotherExternalVar);
Now between anExternalVar and anotherExternalVar there is a pointer like relationship even if the function has exited: the pointed location is suitable to be bequeathed upon expiring. A different language than PHP, like JavaScript, would have probably done it without having to instruct this blatantly with the & sign (maybe you want to read again the end of #2 to remember what JavaScript would do in the same circumstances), but PHP can implement that, from within a function (which undoubtedly is a scope limited block of code), also on primitive data type provided you both apply the & syntax and won't get fooled by expiring pointers lifespans.
|
A CONCEPTUAL AMBIGUITY in pointer policies |
There is a somewhat moot consequence depending upon the policy each scripting or programming language enforces about pointers (which as such are always there) and the relative referencing and dereferencing capabilities (which as such are an opportunity bestowed or not by who invents or develops the language, accordingly to the choice in case).
Some languages as javaScript implement no policy and therefore have what I' ve called stark pointers, whereas the re/dereferencing capabilities can only be accessed through the three strategies as outlined above. Such strategies preserve some validity in all languages, but we can surely imagine different approaches:
- We can envision a language (one of the features that make me speak of a possible javaScript++) where both stark pointers are present along with full referencing and dereferencing syntaxes. Actually, such complete an access is not currently available as far as I know, but this is precisely the policy I am to champion here: javaScript, as I will discuss in deeper details further on, should keep its current stand and add referencing and dreferencing as well: a position many would argue is dangerous for either you have the pointers or you get rid of them once and for all with a full fledged referencing and dreferencing syntax.
But I'd advice otherwise, in fact solutions to programming riddles are good solutions only where their intention is to provide the final user or developer with a more encompassing range of entitlements, and not with a shrinking set, granting in the process that the wedlock between the past and the future proceeds offering a smooth (so called backward) compatibility. This is in my humble opinion the only and safer way to develop, and anyway consider what happened in those instances when such an approach has been rejected: as when AOL acquired Netscape and (I suppose), in order to fill the gap and release as soon as possible the long belated release of the Netscape generation 5 browsers, AOL decided to desert the backward compatibility with the previous Netscape 4 generation Document Object Model, namely the syntax that Netscape 4 would find legitimate, Netscape 5 finds illegal: some are still regretting for this, and no one out here (and neither the AOL chairman himself, actually) has welcomed it as a smart move but as a deplorable "necessity". So when it comes to changing a policy do not subtract: add.
- A language like Perl produces pointers only if you openly instruct the variable to be a pointer: but once it's a pointer, in order to modify its contents, you do have to dereference it first by openly instruct it again with the proper syntax.
- A language like PHP produces pointers if you openly instruct its variables to be a pointer (which's achieved by putting before the variable names an & sign), but requires no syntax to dereference it in order to change the pointed contents (that is: they are immediately accessible for being addressed, under this perspective).
There comes the question: what do we properly mean by saying we're DEreferencing?
Do we mean that we make the pointed contents available to further modification ( Perl) or do we mean that we're putting into the field instructions to make sure that a previously generated pointer variable should quit being a pointer and either:
- let the pointed object be modified (Perl, again)?
- or automatically unfold a new copy form the pointed object so that such variable wouldn't be any longer a pointer but an independent copy?
- or both? (javaScript++ ?)
I myself would support an approach that would hand over a syntax that discriminates all the possibilities, letting the scripter with the wider and ampler spectrum to choose from. And, obviously, the default behaviour should be the current javaScript one: stark pointers. If all these things would be cumulated, that would actually be the correct (in the sense of the less biased) addressing of the pointer phenomenon.
In the section above which I called A Modest Proposal we could therefore drain more flexibility: instance:
(+)aVariable=anotherVar //made a pointer;
(!-)aVariable
whereas the syntax would mean: now dereference (-) and do yield a copy (!), while:
(-)aVariable
might simply mean: dereference and make the contents available without producing a copy: and therefore affecting the original if after such statement I'd change aVariable to be, say, number 5; and -even more- since 5 would be a number and therefore primitive data type, I'd implement it such that, since we openly istructed aVariable was a pointer, now even if it shifted towards primitive data type, none the less even the original must be shifted and be affected (which would call for special attention in case the dereferenced object would be set to null).
In the last part of this file I'm accosting the data type issue more deeply. Anyway if you're slightly more experienced, you may have noticed that my plea for an universal syntax of pointers (or a javaScript++ syntax) is molded on what some strongly data typed languages (and in order to know what a strongly data typed language is and its critical involvements see the last section of this document) call data type casting: in some languages, if you have a stringed version of a number (that is, a number in between quotes, and therefore a String data type) such as:
aVar="14"
let you force it to become a true numerical data type by putting before it a set of round brackets and in between the round brckets the type of data type you want the variable being converted to:
aVar; //or:
aVar
I consider that a referencing and dereferencing policy might be considered, actually, as a casting under misleading dress. Just think of PHP whereas the casting of an Array yields an Object, and consider how the casting of such object back to an array would make available again all those array values whose name would have been illegal to be addressed as properties of the Object data type and that therefore appeared as lost.
Moreover, no doubt that the policy of a casting like syntax matched with the dot syntax (which, actually, is the Java syntax to adress an object property, like:
anObjectgrabItsProperty
) instead of the childish dart like syntax that many languages adopt
(like: anObjectgrabItsProperty)
is a sounder syntax for using an element than the dart one I just reproduced (and which seems so unduly popular), whose unique reason for having been picked and appointed to be even a syntax component of several outstanding languages, is that it looks like a finger (yes: since a pointer points, then let's include an... arrow as a syntax component): an anthropoidal consideration led reasoning, that to my eyes always looked as much reasonable as stepping down from monotheistic cultural background driven considerations, to enter idolatry: for politeism might make sense (st. Augustine even respected it, to some degree), but making of a totem your only god is pretty much naive to my humble mind. So casting and dots should be a good candidate for an universal syntax for pointers.
Moreover you know: programming is already troublesome enough; putting a wavering finger like before its forehead is not going to make it look wiser, and certainly it is not going to make it simpler. You introduce something in a language if what you enclose accomplishes something more than a mere makeup to help out absoulte beginners who can't be such (or won't be such any longer) if they've trudged so far in the simoon to be now raising their eyes upon the beams of the pointers' Sphinx. Give' em a sword, not an arrow.
|
WHAT ARE DATA TYPE DEFINITIONS FOR?
|
|
Many languages require you to define the data types your variable is going to store before you can use it: why is this necessary in many major languages? How does this affect pointers?
|
It is time to spend one word on data types, considering we have just finished heavily mentioning it in the last paragraph of this document.
I've always been busy in my life attempting to understand the logics beneath a rule instead of just settling down with abiding by the rules by route; to my extreme disappointment, most of the times I had a question regarding the why instead of being contented with the how, I always got either clearly incompetent replies (ya say the sin, not the sinner) at least in the sense the "answers" structure showed a lack of the understanding (if not of the conceivability) of the very same nature of the question, or you got no answer at all. So no matter how high the hopes and the great expectations, no matter how hard the trial, no matter how founded the objection, all eventually ended up with me chasing after my daily game alone beyond the river and into the trees: I kill all my preys by myself, in person.
In several major languages, like outstanding C or Java (and won't be pointless here to recall the old saying which quite rightly reminds us that «The only thing Java and JavaScript have in common are the first 4 letters of the name», for still we have several persons that believe Java and JavaScript are the same thing: they only share a partially similar name given their common marketing origin) we have an apparently significant redundancy in the definition of the data type.
Defining a data type means this: soon before declaring a variable meant to hold some data, you write down what is called the signature which most significantly means you write down the data type that variable is going to accept: number, object, string, floating number, whatever. Just for the sake of completeness, another typical element of the signature is, whereas the language calls for it, the accessibility of the variable such as public if whatever part of the script can read/set the variable or protected or private if the opposite is true and only some script sections get the privilege to either read or set the given variable in case. For functions the signature can (or must) even include the data type the function returns, and if it returns nothing none the less the signature wants the signature declaring it as belonging to the so called void return data type.
Why this? Why declaring data type in the signatures?
For the computer has to manage the physical memory: in digital terms every object amounts to a flush of bytes, and this amount is not arbitrary but pinpointed: one char is equivalent to one byte, a String requires a looser amount of space being allocated for it can widely vary, a number which is long can require 20 bytes, a shorter one can require 1 byte (and in fact Java and the alike have sophisticated data signature elements like short and long numeric data types, to mention a few). All this happens because the first thing the computer has to do is to allocate for the given forthcoming object a memory space fit to accept its dimensions properly: it's a memory management affair (and henceforth a hardware issue) what we meet along our way when we have to define data types, and this is the reason it may appear an intruding necessity to some scripters: for it is, in fact it's an hardware and not a software conjured up necessity.
By putting in the signature the data type the variable is going to allocate, you are just helping out the computer to clip a slot of memory from the available memory bulk, in order to properly house the byte size of the newcomer in such niche.
You may have noticed that javaScript requires virtually no signature at all: the computer first reads the value assigned at your newly set variable, and thenceforth works out on its own the data type and the amount of memory it is in want of.
So your question is legitimate: couldn't computers deduce the data type on their own?
Many would flock around you explaining that it's better if you can master your script in a fuller way and declare all the signatures in their tiniest details, and that all this makes them feel empowered with a riper control of their program (some of the several ways of expressing the same blathering is: «I want to be in control of everything»: which is not babble in itself, it is babble considering that you will never be fully in control of a program: programs will always go on being an hostile foe you will have to wrangle with all its life long. So why bothering with an empty claim of a firm control at the spring of the river, when you're doomed to give up the most significant slices of your alleged control at midway, when the brook will turn into a powerful stream able to overwhelm all that ridiculous control by gaining flux vigour and tide fury, capable of swallowing all your programmer's pride up in one mouthful at the subtlest -if not the grossest- and less expected swirl? It can fling you out into the quagmire and let you die there. So saying that the complexity of your signatures makes you feel safer, it's like sifting the dime at the threshold, in order to ingurgitate the camel in the kitchen) and so on with the chatters.
But the answer to your question, my man, is that you're right: computers have an avenue to detect data type on their own, and therefore they should: only constructors are an exception that makes sense (that is: instances of a class prototype that have to be initialized by the agency of keyword new - see further on).
Therefore we have a twofold reality: languages that require strong data type definitions and languages which require it not: but both sides of the matter still end up to the same shore.
Whichever the case, in fact, the problem for the computer itself would go on existing and being addressed in the backstage even if your language doesn't require data type definitions: and therefore even if your language of choice doesn't throw on your way a strong signature definition issue, none the less the computer will go on discriminating (on its own and lifting from your hands such necessity) the data types in the background; namely it will go on allocating appropriate memory recesses accordingly. You must be aware of this undergoing firm reality, or data type is going to be a big mystery for your forever.
Let me single out here two major aspects.
Having memory sectors that have to be allocated is the main reasons pointers can exist: as we said, a pointer is a pointer precisely because it points to one of such memory locations.
Such approach is interesting, and should be kept in any case, even to the cost of emulating it in case some quantic computer in the not so nigh future might make the current memory approach utterly obsolete (a chance that, clearly, whoever projects strongly data typed languages deems as unlikely. But what if it occurs? I mean: the catastrophic outcome would be that it would -my goodness- bury around the clock all the existing programming languages based on data type definitions with their related compilers! it wouldn't just be a hardware revolution but an editorial and software engineering apocalypse compared to which the Y2K would be a nuisance: a nuisance based on the same assumptions: that two digits were enough to represent a year and the situation could not change in the foreseeable future).
What is not indispensable is therefore the definition of the signatures, for the other option which is made available by memory management constraints, namely the capability/necessity to reserve memory sectors, is an option I wouldn't be willing to give up at all and which, though originally a bound, over time proved itself being a sheer advantage: pointers can be precious, as we'll see, and couldn't even exist without such a capability (parceling of the memory field, that is) as their bedrock.
So it's not that data type definition makes no sense: it is that self performed data type definitions would save the language, would make it less mortal, and would remove from the ground an appearence of control of the situation which is very deceptive, gives a false sense of being in a safe haven, and is misleading for it might even end up smuggling instability into your coding instead of control: fail one casting and you compromise one megabyte of code, whose 30% of lines might be of overloaded methods, namely copies of the same method but meant to hold different data type arguments in order to accommodate all the possible data types...! What's economic in this? The very same programmer that makes regular pleas for space saving and despises long scripts making a point of introducing cryptic syntaxes meant to trim 10 bytes, is the very same programmer who makes declarations on the intrinsic goodness of strongly data type approaches for "they grant me so much control": and he never realizes he's championing a contradiction, for you can't fulfill a commitment to do what the commitment prescribes not to do.
Anyway, do not feel debated: a strong data type approach makes sense: simply, I see an hazard where others see a shield and nothing but a shield; and I see an unnecessary complication where other see an improvement and nothing but an improvement, without a candid acknowledgement that some aspects are not convincing (and no wonder, and no man's fault: the program which is fully convincing won't ever be compiled, unless an Angel of the Lord descends from the empyrean meadows in order to whisper into your ears the unheard Aleph of the perfect script, ushering us to the way which leads to the emerald script).
Last but not least, at times in Java or other OOP like C#, you can find statements like:
dataType myVar= new dataType(arguments)
whereas dataType is a placeholder for whatever dataType. The weird thing with such statement is that you declare in the signature that the variable myVar is meant to host a dataType data type object, and then by a constructor you say once again it has to be a new... dataType: the spontaneous question is: wasn't one time enough?
No, it wasn't: myVar could have been meant to allocate another object which was already of the dataType typology, or can be meant to initialize on its own a new brand instance of that dataType: therefore the double definition of the signature is only apparent, for it is simply the consequence of an unified approach that accomodates two different incoming chances of values: either an already previously initialized dataType object, or a new dataType object we initialize right now: the fact that at times a variable initialized as dataType is to house a new dataType, is not enough of a fact to invalidate the syntax which demands you to declare the dataType in the variable signature; you do have to do it anyway, in order to preallocate the memory for those cases when you harbor a dataType typology object already initialized somewhere else in your application and not brought forth from scratch by avail of keyword new.
We may argue that you could skip the signature in those cases you initialize a variable by keyword new assuming the compiler could deduce the dataType at that second stage, at least in these cases: but if you go that far, you're already on the terrain we've discussed so far: the dubious, ambiguous nature of strong data type approaches. Pointers are good, signatures too. But signatures that as a consequence of pointers or of other signature elements' usefulness stretch so far to demand a full blown signature even where the obvious may compensate the explanations, are (in my worthless opinion) a lack of flexibility and not a blessing.
THE UTILITY OF POINTERS
|
|
Another useful aspect of pointers
|
You may have forgotten what we said at the incipit: pointers let you save space and memory potentially in a dramatic way and amount: by pointers' agency, you can avoid making a 50 megabytes object linger around in the RAM memory for maybe one hour slowing down either your PC or your Server; and they allow you to produce (to resort again to the example we set up with) the actual copy of the 50 MB object only when an eventual order (a dereferencing as you recently learned) gets issued ( copy-paste, remember?).
We can make another example, which are linked lists.
Linked lists are objects made up, basically, of two fields: one field carries the basic information, the second field is a location for a pointer to another object instance of the same class. So we may have:
function listObject(arg1, arg2){
this.basicInfo=arg1;
this.pointer=arg2;
}
whereas you can initialize new instances of such an object (which being an object and not primitive data type can be pointed at) as, say:
var foo2=new listObject("Mary Brown", null)
var foo1=new listObject("John Smith", foo2)
If you attentively consider the code, you now have all the tools to understand it: foo1.pointer is a pointer to foo2, it could even manipulate (since pointer are the same thing as you now know) the foo2 contents by some command like:
foo1.pointer.basicInfo="no more Mary Brown"
which would replicate in the pointed object. And a change of whatever field in the foo2 object, would propagate throughout the chain without any need to update the objects that are linked to it by pointers!
Conversely, you may notice foo2 (in a back to front approach) has no pointer ( null) for it's the first one and can't point to an upward object in the ladder.
Such chain of objects may easily sum up thousands of items.
By keeping in mind these simple latest examples, and thinking/elaborating them over a bit, you may device in your future scripts not just ways to work around unexpected and more or less mysterious behaviours whose cause was a pointer, but you could implement quite powerful and thunder like, elegant, astonishing solutions to problems that previously you won't have been able to address so smartly.
Pointers are a pervasive dissemination of a shared property without having to update all the objects meant to partake into it, so they are the bride of OOP (Object Oriented Programming) classes.
Or, again: try envisioning the power of an associative (also called hashed) array whose each entry holds an object ammunitioned with pointers to another list...
There are virtually no limits to the fantasy: by being aware of the tricks pointers can involve, you can implement a whole savvy pointer policy. For in a script nothing is more blasting that the development of a shrewd pointer policy.
If you're curious about linked lists, I have one approach that assembles a linked list in the Animation Managers file, and you certainly can find more resources online.
I simply hope that my approach, which has been cast on the difficulties I myself had to fight with, would be enough if not to enlighten you in the right way, at least to add one resource where the pointer problem gets addressed in a relatively universal way. Whatever the case, have fun knowledge harrier.
Info on Copyright infringements
|