History variables: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added PicoLisp)
imported>Arakov
 
(107 intermediate revisions by 62 users not shown)
Line 1: Line 1:
{{draft task}}
{{task}}
''Storing the history of objects in a program is a common task. Maintaining the history of an object in a program has traditionally required programmers either to write specific code for handling the historical data, or to use a library which supports history logging.''
''Storing the history of objects in a program is a common task.
Maintaining the history of an object in a program has traditionally required programmers either to write specific code for handling the historical data, or to use a library which supports history logging.''


''History variables are variables in a programming language which store not only their current value, but also the values they have contained in the past. Some existing languages do provide support for history variables. However these languages typically have many limits and restrictions on use of history variables.
''History variables are variables in a programming language which store not only their current value, but also the values they have contained in the past. Some existing languages do provide support for history variables. However these languages typically have many limits and restrictions on use of history variables.
''
''


[http://www.bod.com/index.php?id=3435&objk_id=148050 "History Variables: The Semantics, Formal Correctness, and Implementation of History Variables in an Imperative Programming Language" by Mallon and Takaoka]
[http://www.bod.com/index.php?id=3435&objk_id=148050 "History Variables:
The Semantics, Formal Correctness, and Implementation of History Variables
in an Imperative Programming Language" by Mallon and Takaoka]


Concept also discussed on [http://lambda-the-ultimate.org/node/3111 LtU] and [http://www.patents.com/us-7111283.html Patents.com].
Concept also discussed on [http://lambda-the-ultimate.org/node/3111 LtU] and [http://www.patents.com/us-7111283.html Patents.com].
Line 17: Line 20:
* recall the three values.
* recall the three values.


For extra points, if the language of choice does not support history variables, demonstrate how this might be implemented.
<br>For extra points, if the language of choice does not support history variables,
demonstrate how this might be implemented.
<br><br>

=={{header|68000 Assembly}}==
68000 Assembly doesn't support history variables natively. They can be implemented using a stack system.
The 68000 can use push/pop commands on any address register, not just the hardware stack pointer.

<syntaxhighlight lang="68000devpac">HistoryVar equ $100200 ;assume this is work ram.

LEA HistoryVar+4,A0
MOVE.L #$11223344,D0
MOVE.L D0,-(A0) ;store the 32-bit value #$11223344 starting at $100200
MOVE.L #$55667788,D0
MOVE.L D0,-(A0) ;store the 32-bit value #$5566788 at $1001FC
MOVE.L #$AABBCCDD,D0
MOVE.L D0,-(A0) ;store the 32-bit value #$AABBCCDD at $1001F8

;display the history
LEA HistoryVar,A0
MOVE.L (A0),D0 ;load #$11223344 into D0
MOVE.L (-4,A0),D1 ;load #$55667788 into D1
MOVE.L (-8,A0),D2 ;load #$AABBCCDD into D2

jsr PrintHex32 ;unimplemented routine that prints D0 as a 32-bit hex number
mov D1,D0
jsr PrintHex32
mov D2,D0
jsr PrintHex32</syntaxhighlight>

Whether this constitutes a single variable at this point is debatable, because at a hardware level anything you write to a memory address permanently erases what was there, with no way to get it back unless you saved it somewhere else. So storing three values at the same memory location won't maintain the history.

=={{header|Ada}}==

Ada does not natively support history variables -- we have to implement them.

Furthermore, Ada is a strongly typed language -- that means, we would need
to write a history variable type for every basic item type.
Instead, we write a single generic package "History_Variables" that works for any item type.


===Generic Package "History_Variables"===

Specification:

<syntaxhighlight lang="ada">private with Ada.Containers.Indefinite_Vectors;
generic
type Item_Type (<>) is private;
package History_Variables is

type Variable is tagged limited private;

-- set and get current value
procedure Set(V: in out Variable; Item: Item_Type);
function Get(V: Variable) return Item_Type;

-- number of items in history (including the current one)
function Defined(V: Variable) return Natural;

-- non-destructively search for old values
function Peek(V: Variable; Generation: Natural := 1) return Item_Type;
-- V.Peek(0) returns current value; V.Peek(1) the previous value, etc.
-- when calling V.Peek(i), i must be in 0 .. V.Defined-1, else Constraint_Error is raised

-- destructively restore previous value
procedure Undo(V: in out Variable);
-- old V.Peek(0) is forgotten, old V.Peek(i) is new V.Peek(i-1), etc.
-- accordingly, V.Defined decrements by 1
-- special case: if V.Defined=0 then V.Undo does not change V

private
package Vectors is new Ada.Containers.Indefinite_Vectors
(Index_Type => Positive,
Element_Type => Item_Type);

type Variable is tagged limited record
History: Vectors.Vector;
end record;
end History_Variables;</syntaxhighlight>

The implementation of "History_Variables":

<syntaxhighlight lang="ada">package body History_Variables is

-- set and get
procedure Set(V: in out Variable; Item: Item_Type) is
begin
V.History.Prepend(Item);
end Set;

function Get(V: Variable) return Item_Type is
begin
return V.History.First_Element;
end Get;

-- number of items in history (including the current one)
function Defined(V: Variable) return Natural is
begin
return (1 + V.History.Last_Index) - V.History.First_Index;
end Defined;

-- non-destructively search
function Peek(V: Variable; Generation: Natural := 1) return Item_Type is
Index: Positive := V.History.First_Index + Generation;
begin
if Index > V.History.Last_Index then
raise Constraint_Error;
end if;
return V.History.Element(Index);
end Peek;

procedure Undo(V: in out Variable) is
begin
V.History.Delete_First;
end Undo;

end History_Variables;</syntaxhighlight>


===Sample 1: The History of an Integer Variable===

<syntaxhighlight lang="ada">with Ada.Text_IO, History_Variables;

procedure Test_History is

package Int_With_Hist is new History_Variables(Integer);

-- define a history variable
I: Int_With_Hist.Variable;

Sum: Integer := 0;

begin

-- assign three values
I.Set(3);
I.Set(I.Get + 4);
I.Set(9);

-- non-destructively display the history
for N in reverse 0 .. I.Defined-1 loop
Ada.Text_IO.Put(Integer'Image(I.Peek(N)));
end loop;
Ada.Text_IO.New_Line;

-- recall the three values
while I.Defined > 0 loop
Sum := Sum + I.Get;
I.Undo;
end loop;
Ada.Text_IO.Put_Line(Integer'Image(Sum));

end Test_History;</syntaxhighlight>

{{out}}
<pre> 3 7 9
19</pre>


===Sample 2: The History of a String===

<syntaxhighlight lang="ada">with Ada.Text_IO, History_Variables;

procedure Test_History is

package Str_With_Hist is new History_Variables(String);

-- define a history variable
S: Str_With_Hist.Variable;

Sum: Integer := 0;

begin

-- assign three values
S.Set("one");
S.Set(S.Get & S.Get); --"oneone"
S.Set("three");

-- non-destructively display the history
for N in reverse 0 .. S.Defined-1 loop
Ada.Text_IO.Put(S.Peek(Generation => N) &" ");
end loop;
Ada.Text_IO.New_Line;

-- recall the three values
while S.Defined > 0 loop
Sum := Sum + S.Get'Length;
S.Undo;
end loop;
Ada.Text_IO.Put_Line(Integer'Image(Sum));

end Test_History;</syntaxhighlight>

{{out}}
<pre>one oneone three
14</pre>

=={{header|ALGOL W}}==
Algol W does not have history variables as standard, as with other languages here, we can add them using a simple linked list.
<br>As Algol W does not have generic types, a separate history variable type would be required for each type of variable.
<syntaxhighlight lang="algolw">begin
% implements integer history variables %
% similar history types could be defined for other types of variable %
record HInteger ( integer iValue; reference(HInteger) iPrev );
% sets the latest value of hv to n %
procedure setIhv ( reference(HInteger) value result hv; integer value n ) ; hv := HInteger( n, hv );
% declare an integer history variable %
reference(HInteger) hv;
% initialise the history to a null value %
hv := null;
% assign three values %
setIhv( hv, 1 );
setIhv( hv, 2 );
setIhv( hv, 3 );
% show the history of hv %
begin
reference(HInteger) h;
write( "hv history: " );
h := hv;
while h not = null do begin
writeon( i_w := 3, s_w := 0, iValue(h), " " );
h := iPrev(h)
end while_h_ne_null
end;
% remove the values from hv, summing them as in the Ada sample %
begin
integer s;
s := 0;
while hv not = null do begin
s := s + iValue(hv);
hv := iPrev(hv)
end while_hv_ne_null ;
write( "Sum of the historic values: ", s )
end
end.</syntaxhighlight>
{{out}}
<pre>
hv history: 3 2 1
Sum of the historic values: 6
</pre>

=={{header|Arturo}}==
<syntaxhighlight lang="arturo">define :history [][
init: [
this\record: @[0]
]
]
assign: function [historyVar,newValue][
historyVar\record: historyVar\record ++ newValue
]

alias.infix {'-->} 'assign

records: function [historyVar][
historyVar\record
]

retrieve: function [historyVar][
result: last historyVar\record
historyVar\record: chop historyVar\record
return result
]

current: function [historyVar][
return last historyVar\record
]

do [
h: to :history []

print "Assigning three values: 1, 2, 3..."
h --> 1
h --> 2
h --> 3

print "\nHistory (oldest values first):"
print [">" records h]

print ["\nCurrent value is:" current h]

print "\nRecalling the three values..."
loop 1..3 'x ->
print ["- Recalled:" retrieve h]

print "\nHistory:"
print [">" records h]
]</syntaxhighlight>

{{out}}

<pre>Assigning three values: 1, 2, 3...

History (oldest values first):
> [0 1 2 3]

Current value is: 3

Recalling the three values...
- Recalled: 3
- Recalled: 2
- Recalled: 1

History:
> [0] </pre>

=={{header|AspectJ}}==
AspectJ implementation for Java 7.
Type of the history variable (Java class):
<syntaxhighlight lang="java">public class HistoryVariable
{
private Object value;

public HistoryVariable(Object v)
{
value = v;
}

public void update(Object v)
{
value = v;
}

public Object undo()
{
return value;
}

@Override
public String toString()
{
return value.toString();
}

public void dispose()
{
}
}</syntaxhighlight>
Aspect (HistoryHandling.aj):
<syntaxhighlight lang="java">import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

public privileged aspect HistoryHandling
{
before() : execution(HistoryVariable.new(..))
{
history.put((HistoryVariable) thisJoinPoint.getTarget(), new LinkedList<>());
}

after() : execution(void HistoryVariable.dispose())
{
history.remove(thisJoinPoint.getTarget());
}

before(Object v) : execution(void HistoryVariable.update(Object)) && args(v)
{
final HistoryVariable hv = (HistoryVariable) thisJoinPoint.getThis();
history.get(hv).add(hv.value);
}

after() : execution(Object HistoryVariable.undo())
{
final HistoryVariable hv = (HistoryVariable) thisJoinPoint.getThis();
final Deque<Object> q = history.get(hv);
if (!q.isEmpty())
hv.value = q.pollLast();
}

String around() : this(HistoryVariable) && execution(String toString())
{
final HistoryVariable hv = (HistoryVariable) thisJoinPoint.getThis();
final Deque<Object> q = history.get(hv);
if (q == null)
return "<disposed>";
else
return "current: "+ hv.value + ", previous: " + q.toString();
}

private Map<HistoryVariable, Deque<Object>> history = new HashMap<>();
}</syntaxhighlight>
Usage:
<syntaxhighlight lang="java">public final class Main
{
public static void main(final String[] args)
{
HistoryVariable hv = new HistoryVariable("a");
hv.update(90);
hv.update(12.1D);
System.out.println(hv.toString());
System.out.println(hv.undo());
System.out.println(hv.undo());
System.out.println(hv.undo());
System.out.println(hv.undo());
System.out.println(hv.toString());
hv.dispose();
System.out.println(hv.toString());
}
}</syntaxhighlight>

{{out}}
<pre>current: 12.1, previous: [a, 90]
12.1
90
a
a
current: a, previous: []
<disposed></pre>

=={{header|AutoHotkey}}==
AutoHotkey records a history of your keypresses, but not your variables. The closest you can come is with a class:
{{works with|AutoHotkey 1.1}}
<syntaxhighlight lang="ahk">HV := new HistoryVariable
HV.var := 1
HV.var := 2
HV.var := "Latest value"
Msgbox % HV.var "`n" HV[2] "`n" HV[3]

class HistoryVariable {
__Set(aName, aValue) {
this.Insert(1,aValue)
Return aValue
}
__Get(aName) {
Return this[1]
}
}</syntaxhighlight>

=={{header|C sharp}}==
<syntaxhighlight lang="c sharp">using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace History
{
class Program
{
static void Main(string[] args)
{
var h = new HistoryObject();
h.Value = 5;
h.Value = "foo";
h.Value += "bar";

var history = h.ToArray();

for (int i = 0; i < history.Length; i++)
{
Console.Write("{0}{1}", history[i], ((i >= history.Length - 1) ? "\n" : " <- "));
}

h.Undo();
h.Undo();
h.Undo();

Console.WriteLine(h.Value);
}

private class HistoryObject : IEnumerable<object>
{
public HistoryObject()
{
_history = new Stack<object>(); // Initiates the history stack.
}

public object Value
{
get // Returns the top value from the history if there is one. Otherwise null.
{
if (_history.Count > 0)
return _history.Peek();
return null;
}
set { _history.Push(value); } // Adds the specified value to the history.
}

public void Undo()
{
if (_history.Count > 0)
_history.Pop(); // Removes the current value from the history.
}

// History stack that will hold all previous values of the object.
private readonly Stack<object> _history;

public IEnumerator<object> GetEnumerator()
{
return _history.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
}</syntaxhighlight>

{{out}}
<pre>foobar <- foo <- 5
</pre>

=={{header|C++}}==
C++ does not have history variables, but they can easily by implemented with a generic class.
<syntaxhighlight lang="c++">
#include <deque>
#include <iostream>
#include <string>

template <typename T>
class with_history {
public:
with_history(const T& element) {
history.push_front(element);
}

T get() {
return history.front();
}

void set(const T& element) {
history.push_front(element);
}

std::deque<T> get_history() {
return std::deque<T>(history);
}

T rollback() {
if ( history.size() > 1 ) {
history.pop_front();
}
return history.front();
}

private:
std::deque<T> history;
};

int main() {
with_history<double> number(1.2345);
std::cout << "Current value of number: " << number.get() << std::endl;

number.set(3.4567);
number.set(5.6789);

std::cout << "Historical values of number: ";
for ( const double& value : number.get_history() ) {
std::cout << value << " ";
}
std::cout << std::endl << std::endl;

with_history<std::string> word("Goodbye");
word.set("Farewell");
word.set("Hello");

std::cout << word.get() << std::endl;
word.rollback();
std::cout << word.get() << std::endl;
word.rollback();
std::cout << word.get() << std::endl;
word.rollback();
std::cout << word.get() << std::endl;
word.rollback();
}
</syntaxhighlight>
{{ out }}
<pre>
Current value of number: 1.2345
Historical values of number: 5.6789 3.4567 1.2345

Hello
Farewell
Goodbye
Goodbye
</pre>

=={{header|Clojure}}==
Clojure does not have history variables, but it can be accomplished
via a watcher function that can track changes on a variable.

<syntaxhighlight lang="clojure">
(def a (ref 0))
(def a-history (atom [@a])) ; define a history vector to act as a stack for changes on variable a
(add-watch a :hist (fn [key ref old new] (swap! a-history conj new)))
</syntaxhighlight>

{{out|Sample Output}}
<pre>user=> (dosync (ref-set a 1))
1
user=> (dosync (ref-set a 2))
2
user=> (dosync (ref-set a 3))
3
user=> @a-history
[0 1 2 3]
user=> (dotimes [n 3] (println (peek @a-history)) (swap! a-history pop))
3
2
1
nil
user=> @a-history
[0]
</pre>

=={{header|Common Lisp}}==
In Lisp the list is a natural and simple data structure for representing variables with history. By adding some simple macros we can make a small DSL that hides the list and makes it look like a history variable is it's own special thing.

<syntaxhighlight lang="lisp">(defmacro make-hvar (value)
`(list ,value))

(defmacro get-hvar (hvar)
`(car ,hvar))

(defmacro set-hvar (hvar value)
`(push ,value ,hvar))

;; Make sure that setf macro can be used
(defsetf get-hvar set-hvar)

(defmacro undo-hvar (hvar)
`(pop ,hvar))

(let ((v (make-hvar 1)))
(format t "Initial value = ~a~%" (get-hvar v))
(set-hvar v 2)
(setf (get-hvar v) 3) ;; Alternative using setf
(format t "Current value = ~a~%" (get-hvar v))
(undo-hvar v)
(undo-hvar v)
(format t "Restored value = ~a~%" (get-hvar v)))
</syntaxhighlight>
{{out}}
<pre>Initial value = 1
Current value = 3
Restored value = 1
</pre>

=={{header|D}}==
D does not have history variables. The following implementation provides a generic HistoryVariable that protects the historical values by defining them as 'const'.

<syntaxhighlight lang="d">import std.stdio, std.array, std.string, std.datetime, std.traits;

/// A history variable.
struct HistoryVariable(T) {
/// A value in a point in time.
static struct HistoryValue {
SysTime time;
T value;

// Alternative to the more common toString.
//void toString(scope void delegate(string) output) const {
void toString(scope void delegate(const(char)[]) output)const {
output(format("%s; %s", time, value));
}
}

const(HistoryValue)[] values;

private void addValue(T value) {
values ~= HistoryValue(Clock.currTime(), value);
}

void opAssign(T value) {
addValue(value);
}

@property T currentValue() const pure nothrow {
return values.back.value;
}

alias currentValue this;

@property auto history() const pure nothrow {
return values;
}

/**
Demonstrating D's compile-time reflection features. The member
functions that are in this 'static if' block would be added for
types T that are arrays (including strings). */
static if (isArray!T) {
// Append-with-assign operator.
void opOpAssign(string op : "~")(T element) {
addValue(currentValue ~ element);
}

// Similar implementation for other array operators...
}
}

void main() {
HistoryVariable!int x;
x = 1;
x = 2;
x = 3;
writefln("%(%s\n%)\n", x.history);

HistoryVariable!string s;
s = "hello";
s ~= " world";
s = "goodby";
writefln("%(%s\n%)", s.history);
}</syntaxhighlight>
{{out|Sample Output}}
<pre>2013-Jan-19 23:04:55.1660302; 1
2013-Jan-19 23:04:55.1660407; 2
2013-Jan-19 23:04:55.1660424; 3

2013-Jan-19 23:04:55.1662551; hello
2013-Jan-19 23:04:55.1662581; hello world
2013-Jan-19 23:04:55.1662596; goodby
</pre>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
<syntaxhighlight lang="delphi">
program History_variables;

{$APPTYPE CONSOLE}

uses
System.SysUtils;

type
THistoryVarType = record
value: variant;
timestamp: TDateTime;
function ToString: string;
end;

THistoryVar = record
Fvalue: variant;
FHistory: TArray<THistoryVarType>;
private
procedure SetValue(const Value: Variant);
function GetTimestamp: TDateTime;
public
property History: TArray<THistoryVarType> read FHistory;
constructor Init(val: variant);
function Dump: string;
function Recall(steps: Integer): variant; overload;
function Recall(timestamp: TDateTime): variant; overload;
property Timestamp: TDateTime read GetTimestamp;
property Value: Variant read Fvalue write SetValue;
end;

{ THistoryVar }

function THistoryVar.Dump: string;
begin
Result := '';
for var h in FHistory do
Result := Result + h.ToString + #10;
end;

function THistoryVar.GetTimestamp: TDateTime;
begin
if Length(FHistory) = 0 then
exit(0);
Result := FHistory[high(FHistory)].timestamp;
end;

constructor THistoryVar.Init(val: variant);
begin
SetLength(Fhistory, 0);
SetValue(val);
end;

function THistoryVar.Recall(timestamp: TDateTime): variant;
begin
for var h in FHistory do
begin
if h.timestamp = timestamp then
exit(h.value);
end;
result := Fvalue;
end;

function THistoryVar.Recall(steps: Integer): variant;
begin
if (steps <= 1) or (steps >= Length(FHistory)) then
exit(value);

result := FHistory[Length(FHistory) - steps - 1].value;
end;

procedure THistoryVar.SetValue(const Value: Variant);
begin
SetLength(FHistory, Length(FHistory) + 1);
FHistory[High(FHistory)].Value := Value;
FHistory[High(FHistory)].timestamp := now;
Fvalue := Value;
end;

{ THistoryVarType }

function THistoryVarType.ToString: string;
var
dt: string;
begin
DateTimeToString(dt, 'mm/dd/yyyy hh:nn:ss.zzz', timestamp);
Result := format('%s - %s', [dt, Value]);
end;

begin
var v := THistoryVar.Init(0);
v.Value := True;

Sleep(200);
if v.Value then
v.Value := 'OK';

Sleep(100);
if v.Value = 'OK' then
v.Value := PI;

writeln('History of variable values:'#10);
Writeln(v.Dump);

Writeln('Recall 2 steps');
Writeln(v.Recall(2));

var t := v.History[3].timestamp;
Writeln(#10'Recall to timestamp ', datetimetostr(t));
Writeln(v.Recall(t));

readln;
end.</syntaxhighlight>
{{out}}
<pre>History of variable values:

02/28/2021 19:50:32.512 - 0
02/28/2021 19:50:32.512 - True
02/28/2021 19:50:32.712 - OK
02/28/2021 19:50:32.813 - 3,14159265358979

Recall 2 steps
True

Recall to timestamp 28/02/2021 19:50:32
3,14159265358979</pre>

=={{header|EchoLisp}}==
No native support. We implement an anonymous stack associated with the variable, and a few syntax rules to define the needed operations.
<syntaxhighlight lang="lisp">
(define-syntax-rule (make-h-var name) (define name (stack (gensym))))
(define-syntax-rule (h-get name) (stack-top name))
(define-syntax-rule (h-set name value) (push name value))
(define-syntax-rule (h-undo name)
(begin
(pop name)
(when ( stack-empty? name) (error "no more values" 'name))
(stack-top name)))
(define-syntax-rule (h-values name) (stack->list name))
;; usage
(make-h-var x)→ x

(h-set x 42) → 42
(h-set x 666)→ 666
(h-set x 'elvis)→ elvis
(h-values x) → (42 666 elvis) ;; historized values

(h-get x) → elvis
(h-undo x)→ 666
(h-undo x) → 42
(h-undo x) → ❌ error: no more values x
</syntaxhighlight>

=={{header|Elena}}==
ELENA 6.x :
<syntaxhighlight lang="elena">import extensions;
import system'collections;
import system'routines;
import extensions'routines;
class HistoryVariable
{
Stack previous := new Stack();
object value;
Value
{
get() = value;
set(value)
{
if ((this value) != nil)
{
previous.push(this value)
};
this value := value
}
}
undo()
{
ifnot (previous.isEmpty())
{
value := previous.pop()
}
else
{
value := nil
}
}
enumerator() => previous;
string toPrintable() => this value;
}
public program()
{
var o := new HistoryVariable();
o.Value := 5;
o.Value := "foo";
o.Value := o.Value + "bar";
console.printLine(o);
o.forEach(printingLn);
o.undo().undo().undo();
console.printLine(o.Value ?? "nil")
}</syntaxhighlight>
{{out}}
<pre>
foobar
foo
5
nil
</pre>

=={{header|Erlang}}==
If we consider the usage of history variables, like not losing the old value by mistake or having a way to get an old value, then Erlang can really help. Being single assignment Erlang will not allow you to lose an old value, and it is certain that the previous values are always there. The downside is that you must handle this manually.

{{out}}
<pre>
1> V1 = "123".
"123"
2> V1 = V1 ++ "qwe".
** exception error: no match of right hand side value "123qwe"
3> V2 = V1 ++ "qwe".
"123qwe"
4> V3 = V2 ++ "ASD".
"123qweASD"
5> V1.
"123"
6> V2.
"123qwe"
7> V3.
"123qweASD"
</pre>

=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: accessors combinators formatting kernel models.history ;

1 <history> {
[ add-history ]
[ value>> "Initial value: %u\n" printf ]
[ 2 >>value add-history ]
[ 3 swap value<< ]
[ value>> "Current value: %u\n" printf ]
[ go-back ]
[ go-back ]
[ value>> "Restored value: %u\n" printf ]
} cleave</syntaxhighlight>
{{out}}
<pre>
Initial value: 1
Current value: 3
Restored value: 1
</pre>

=={{header|Forth}}==
Forth does not have history variables, but it is trivial to define them. This one uses a linked list. The history variable is initialized to zero to avoid expensive sanity checks in ''H@''. ''H--'' undoes the assignment of a value and effectively returns a history variable to its former state.
<syntaxhighlight lang="forth">: history create here cell+ , 0 , -1 , ;
: h@ @ @ ;
: h! swap here >r , dup @ , r> swap ! ;
: .history @ begin dup cell+ @ -1 <> while dup ? cell+ @ repeat drop ;
: h-- dup @ cell+ @ dup -1 = if abort" End of history" then swap ! ;</syntaxhighlight>

A sample session:
<pre>
history z ok
23 z h! ok
z h@ . 23 ok
34 z h! ok
z h@ . 34 ok
45 z h! ok
z h@ . 45 ok
z .history 45 34 23 ok
z dup h-- h@ . 34 ok
z dup h-- h@ . 23 ok
z dup h-- h@ . 0 ok
z dup h-- h@ .
:86: End of history
</pre>

=={{header|Go}}==
We're all in this for the extra points. Mallon and Takota seem happy with sequences, but time and timestamps were mentioned on LtU. Beyond a separate sequence for each history variable, timestamps enable multiple variables to be seen in a common temporal sequence. In Go, with it's attention to concurrency, this might be done with flexibility for proper handling of shared variables, and efficient handling of variables limited to a single thread.
<syntaxhighlight lang="go">package main

import (
"fmt"
"sort"
"sync"
"time"
)

// data type for history variable (its an int)
type history struct {
timestamp tsFunc
hs []hset
}

// data type for timestamp generator
type tsFunc func() time.Time

// data type for a "set" event
type hset struct {
int // new value
t time.Time // timestamp
}

// newHistory creates a history variable
func newHistory(ts tsFunc) history {
return history{ts, []hset{{t: ts()}}}
}
// int returns the current value
func (h history) int() int {
return h.hs[len(h.hs)-1].int
}
// set does what you expect and returns the timestamp recorded for the event
func (h *history) set(x int) time.Time {
t := h.timestamp()
h.hs = append(h.hs, hset{x, t})
return t
}

// dump displays a complete history
func (h history) dump() {
for _, hs := range h.hs {
fmt.Println(hs.t.Format(time.StampNano), hs.int)
}
}
// recall recalls the value stored in the history variable at time t.
// if the variable had not been created yet, ok is false.
func (h history) recall(t time.Time) (int, /*ok*/ bool) {
i := sort.Search(len(h.hs), func(i int) bool {
return h.hs[i].t.After(t)
})
if i > 0 {
return h.hs[i-1].int, true
}
return 0, false
}

// newTimestamper returns a function that generates unique timestamps.
// Use a single timestamper for multiple history variables to preserve
// an unambiguous sequence of assignments across the multiple history
// variables within a single goroutine.
func newTimestamper() tsFunc {
var last time.Time
return func() time.Time {
if t := time.Now(); t.After(last) {
last = t
} else {
last.Add(1)
}
return last
}
}

// newProtectedTimestamper generates unique timestamps for concurrent
// goroutines.
func newProtectedTimestamper() tsFunc {
var last time.Time
var m sync.Mutex
return func() (t time.Time) {
t = time.Now()
m.Lock() // m protects last
if t.After(last) {
last = t
} else {
last.Add(1)
t = last
}
m.Unlock()
return
}
}

func main() {
// enable history variable support appropriate for single goroutine.
ts := newTimestamper()
// define a history variable
h := newHistory(ts)
// assign three values. (timestamps kept for future reference.)
ref := []time.Time{h.set(3), h.set(1), h.set(4)}
// non-destructively display history
fmt.Println("History of variable h:")
h.dump()
// recall the three values. (this is non-destructive as well, but
// different than the dump in that values are recalled by time.)
fmt.Println("Recalling values:")
for _, t := range ref {
rv, _ := h.recall(t)
fmt.Println(rv)
}
}</syntaxhighlight>
{{out}}
<pre>
History of variable h:
Dec 3 18:51:17.292260000 0
Dec 3 18:51:17.292262000 3
Dec 3 18:51:17.292264000 1
Dec 3 18:51:17.292270000 4
Recalling values:
3
1
4
</pre>

=={{header|Haskell}}==

There are no native Haskell history variables, but they are simple to implement.

<syntaxhighlight lang="haskell">import Data.IORef

newtype HVar a = HVar (IORef [a])

newHVar :: a -> IO (HVar a)
newHVar value = fmap HVar (newIORef [value])

readHVar :: HVar a -> IO a
readHVar (HVar ref) = fmap head (readIORef ref)

writeHVar :: a -> HVar a -> IO ()
writeHVar value (HVar ref) = modifyIORef ref (value:)

undoHVar :: HVar a -> IO ()
undoHVar (HVar ref) = do
(_ : history) <- readIORef ref
writeIORef ref history

getHistory :: HVar a -> IO [a]
getHistory (HVar ref) = readIORef ref

-- Testing
main :: IO ()
main = do
var <- newHVar 0
writeHVar 1 var
writeHVar 2 var
writeHVar 3 var
getHistory var >>= print
undoHVar var
undoHVar var
undoHVar var</syntaxhighlight>


=={{header|J}}==
=={{header|J}}==
Line 23: Line 1,193:
J does not natively support "history variables", but the functionality is easy to add:
J does not natively support "history variables", but the functionality is easy to add:


<lang j>varref_hist_=:'VAR','_hist_',~]
<syntaxhighlight lang="j">varref_hist_=:'VAR','_hist_',~]
set_hist_=:4 :0
set_hist_=:4 :0
V=.varref x
V=.varref x
Line 34: Line 1,204:
)
)
length_hist_=: #@getall
length_hist_=: #@getall
get_hist_=: _1 {:: getall</lang>
get_hist_=: _1 {:: getall</syntaxhighlight>


Example use:
Example use:


<lang j> 'x' set_hist_ 9
<syntaxhighlight lang="j"> 'x' set_hist_ 9
9
9
'x' set_hist_ 10
'x' set_hist_ 10
Line 51: Line 1,221:
┌─┬──┬──┐
┌─┬──┬──┐
│9│10│11│
│9│10│11│
└─┴──┴──┘</lang>
└─┴──┴──┘</syntaxhighlight>


Note that each value is contained in a box, so different values do not need to be type compatible with each other. If this is considered a defect then assertions could be added to enforce type compatibility across assignments.
Note that each value is contained in a box, so different values do not need to be type compatible with each other. If this is considered a defect then assertions could be added to enforce type compatibility across assignments.
Line 57: Line 1,227:
Note that only nouns are supported here: If you want to store verbs using this mechanism you will need to use their gerunds.
Note that only nouns are supported here: If you want to store verbs using this mechanism you will need to use their gerunds.


Finally, note that the distinction between relevant history and irrelevant history depend on the application, and perhaps on the user. Also, necessity suggests that a lot of the history detail will be irrelevant for many purposes.
=={{header|PicoLisp}}==
<lang PicoLisp>(de setH ("Var" Val)
(when (val "Var")
(with "Var"
(=: history (cons @ (: history))) ) )
(set "Var" Val) )


=={{header|Java}}==
(de restoreH ("Var")
Java does not support history variables, but they are easy to implement using the lists that come with Java's Collections framework.
(set "Var" (pop (prop "Var" 'history))) )</lang>
Test:
<pre>: (setH 'A "Hello world")
-> "Hello world"


===Java Integer with History===
: (setH 'A '(a b c d))
This implementation does not allow the History Variable to be "empty". It can be assigned one or multiple "nulls", but it can never have an undefined value (such as being created and not initialized).
-> (a b c d)
<syntaxhighlight lang="java">import java.util.Collections;
import java.util.LinkedList;
import java.util.List;


/**
: (setH 'A 123)
* A class for an "Integer with a history".
-> 123
* <p>
* Note that it is not possible to create an empty Variable (so there is no "null") with this type. This is a design
* choice, because if "empty" variables were allowed, reading of empty variables must return a value. Null is a
* bad idea, and Java 8's Optional<T> (which is somewhat like the the official fix for the null-bad-idea) would
* make things more complicated than an example should be.
*/
public class IntegerWithHistory {


/**
: A
* The "storage Backend" is a list of all values that have been ever assigned to this variable. The List is
-> 123
* populated front to back, so a new value is inserted at the start (position 0), and older values move toward the end.
*/
private final List<Integer> history;


/**
: (get 'A 'history)
* Creates this variable and assigns the initial value
-> ((a b c d) "Hello world")
*
* @param value initial value
*/
public IntegerWithHistory(Integer value) {
history = new LinkedList<>();
history.add(value);
}


/**
: (restoreH 'A)
* Sets a new value, pushing the older ones back in the history
-> (a b c d)
*
* @param value the new value to be assigned
*/
public void set(Integer value) {
//History is populated from the front to the back, so the freshest value is stored a position 0
history.add(0, value);
}


/**
: (restoreH 'A)
* Gets the current value. Since history is populuated front to back, the current value is the first element
-> "Hello world"
* of the history.
*
* @return the current value
*/
public Integer get() {
return history.get(0);
}


/**
: A
* Gets the entire history all values that have been assigned to this variable.
-> "Hello world"
*
* @return a List of all values, including the current one, ordered new to old
*/
public List<Integer> getHistory() {
return Collections.unmodifiableList(this.history);
}


/**
: (restoreH 'A)
* Rolls back the history one step, so the current value is removed from the history and replaced by it's predecessor.
-> NIL</pre>
* This is a destructive operation! It is not possible to rollback() beyond the initial value!
*
* @return the value that had been the current value until history was rolled back.
*/
public Integer rollback() {
if (history.size() > 1) {
return history.remove(0);
} else {
return history.get(0);
}
}
}
</syntaxhighlight>
Test Program:
<syntaxhighlight lang="java">public class TestIntegerWithHistory {

public static void main(String[] args) {

//creating and setting three different values
IntegerWithHistory i = new IntegerWithHistory(3);
i.set(42);
i.set(7);

//looking at current value and history
System.out.println("The current value of i is :" + i.get());
System.out.println("The history of i is :" + i.getHistory());

//demonstrating rollback
System.out.println("Rolling back:");
System.out.println("returns what was the current value: " + i.rollback());
System.out.println("after rollback: " + i.get());
System.out.println("returns what was the current value: " + i.rollback());
System.out.println("after rollback: " + i.get());
System.out.println("Rolling back only works to the original value: " + i.rollback());
System.out.println("Rolling back only works to the original value: " + i.rollback());
System.out.println("So there is no way to 'null' the variable: " + i.get());

}
}</syntaxhighlight>

{{out}}
<pre>
The current value of i is :7
The history of i is :[7, 42, 3]
Rolling back:
returns what was the current value: 7
after rollback: 42
returns what was the current value: 42
after rollback: 3
Rolling back only works to the original value: 3
Rolling back only works to the original value: 3
So there is no way to 'null' the variable: 3
</pre>

===Java History for "any class" using Generics===
This implementation does not allow the History Variable to be "empty". It can be assigned one or multiple "nulls", but it can never have an undefined value (such as being created and not initialized).
Test Program using a "String with History":
<syntaxhighlight lang="java">import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
* A Generic class for an "Anything with a history".
* <p>
* Note that it is not possible to create an empty Variable (so there is no "null") with this type. This is a design
* choice, because if "empty" variables were allowed, reading of empty variables must return a value. Null is a
* bad idea, and Java 8's Optional<T> (which is somewhat like the the official fix for the null-bad-idea) would
* make things more complicated than an example should be.
* <p>
* Also note that this "really works" only with constant Ts. If somebody keeps a reference to an assigned value,
* and is able to modify the state of this value through the reference , this will not be reflected in the history!
*/
public class WithHistory<T> {

/**
* The "storage Backend" is a list of all values that have been ever assigned to this variable. The List is
* populated front to back, so a new value is inserted at the start (position 0), and older values move toward the end.
*/
private final List<T> history;

/**
* Creates this variable and assigns the initial value
*
* @param value initial value
*/
public WithHistory(T value) {
history = new LinkedList<>();
history.add(value);
}

/**
* Sets a new value, pushing the older ones back in the history
*
* @param value the new value to be assigned
*/
public void set(T value) {
//History is populated from the front to the back, so the freshest value is stored a position 0
history.add(0, value);
}

/**
* Gets the current value. Since history is populuated front to back, the current value is the first element
* of the history.
*
* @return the current value
*/
public T get() {
return history.get(0);
}

/**
* Gets the entire history all values that have been assigned to this variable.
*
* @return a List of all values, including the current one, ordered new to old
*/
public List<T> getHistory() {
return Collections.unmodifiableList(this.history);
}

/**
* Rolls back the history one step, so the current value is removed from the history and replaced by it's predecessor.
* This is a destructive operation! It is not possible to rollback() beyond the initial value!
*
* @return the value that had been the cueent value until history was rolled back.
*/
public T rollback() {
if (history.size() > 1) {
return history.remove(0);
} else {
return history.get(0);
}
}
}
</syntaxhighlight>
{{out}}
<pre>
The current value is :And now to something completely different.
The history is:[And now to something completely different., See you later History!, Hello History!]
Rolling back:
returns what was the current value: And now to something completely different.
after rollback: See you later History!
returns what was the current value: See you later History!
after rollback: Hello History!
Rolling back only works to the original value: Hello History!
Rolling back only works to the original value: Hello History!
So there is no way to 'null' the variable: Hello History!

</pre>

=={{header|Julia}}==
Julia currently does not support overloading the assignment "=" operator.
<syntaxhighlight lang="julia">mutable struct Historied
num::Number
history::Vector{Number}
Historied(n) = new(n, Vector{Number}())
end

assign(y::Historied, z) = (push!(y.history, y.num); y.num = z; y)

x = Historied(1)

assign(x, 3)
assign(x, 5)
assign(x, 4)

println("Past history of variable x: $(x.history). Current value is $(x.num)")
</syntaxhighlight>{{output}}<pre>Past history of variable x: Number[1, 3, 5]. Current value is 4</pre>

=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.1.4

class HistoryVariable<T>(initialValue: T) {
private val history = mutableListOf<T>()

var currentValue: T
get() = history[history.size - 1]
set(value) {
history.add(value)
}

init {
currentValue = initialValue
}

fun showHistory() {
println("The variable's history, oldest values first, is:")
for (item in history) println(item)
}
}

fun main(args: Array<String>) {
val v = HistoryVariable(1)
v.currentValue = 2
v.currentValue = 3
v.showHistory()
println("\nCurrentvalue is ${v.currentValue}")
}</syntaxhighlight>

{{out}}
<pre>
The variable's history, oldest values first, is:
1
2
3

Currentvalue is 3
</pre>

=={{header|Lua}}==
Lua does not natively support history variables. However, as with other languages here, something roughly equivalent could be implemented with a "stack wrapper". The only complicated issue might be how to treat nil's (null values). The implementation below allows initial nil's, and allows undo()'s back to nil, but does <i>not</i> consider nil as part of the "history".
===Via metatable===
<syntaxhighlight lang="lua">-- History variables in Lua 6/12/2020 db
local HistoryVariable = {
new = function(self)
return setmetatable({history={}},self)
end,
get = function(self)
return self.history[#self.history]
end,
set = function(self, value)
self.history[#self.history+1] = value
end,
undo = function(self)
self.history[#self.history] = nil
end,
}
HistoryVariable.__index = HistoryVariable

local hv = HistoryVariable:new()
print("defined:", hv)
print("value is:", hv:get())
--
hv:set(1); print("set() to:", hv:get())
hv:set(2); print("set() to:", hv:get())
hv:set(3); print("set() to:", hv:get())
--
print("history:", table.concat(hv.history,","))
--
hv:undo(); print("undo() to:", hv:get())
hv:undo(); print("undo() to:", hv:get())
hv:undo(); print("undo() to:", hv:get())</syntaxhighlight>
{{out}}
<pre>defined: table: 0000000000939240
value is: nil
set() to: 1
set() to: 2
set() to: 3
history: 1,2,3
undo() to: 2
undo() to: 1
undo() to: nil</pre>
===Via closure===
If a desire is to keep history private and immutable, then..
<syntaxhighlight lang="lua">-- History variables in Lua 6/12/2020 db
local function HistoryVariable()
local history = {}
return {
get = function()
return history[#history]
end,
set = function(value)
history[#history+1] = value
end,
undo = function()
history[#history] = nil
end,
getHistory = function()
local clone = {}
for k,v in pairs(history) do clone[k]=v end
return clone
end
}
end

local hv = HistoryVariable()
print("defined:", hv)
print("value is:", hv.get())
--
hv.set(1); print("set() to:", hv.get())
hv.set(2); print("set() to:", hv.get())
hv.set(3); print("set() to:", hv.get())
--
print("history:", table.concat(hv.getHistory(),","))
--
hv.undo(); print("undo() to:", hv.get())
hv.undo(); print("undo() to:", hv.get())
hv.undo(); print("undo() to:", hv.get())</syntaxhighlight>
{{out}}
<pre>defined: table: 0000000000a59500
value is: nil
set() to: 1
set() to: 2
set() to: 3
history: 1,2,3
undo() to: 2
undo() to: 1
undo() to: nil</pre>

=={{header|M2000 Interpreter}}==
We can make objects type of Group to act as History Variables. Each group has a pointer to a stack object (a linked list).
First we see how we work with Stack (each module/function see a "current stack", we can make pointers to new stacks, but we can't get pointer of current stack). There are some statement no demonstrate here, such as Shift and ShiftBack (move top to a place, and move back to top), and Over (make new items by copying items).

<syntaxhighlight lang="m2000 interpreter">
Flush ' empty curtrent stack
\\ a is a pointer to a new stack object
a=stack:=1,2@,3%
Print Len(A)=3
For i=1 to Len(a) {
Print StackType$(a, i)="Number"
}
b=stack
Print len(b)=0
Push 1, 2 \\ to current stack
Stack b {
\\ make b the current stack
Data 1, 2, 3
} ' Data add to bottom
\\ now current stack get the old object
Stack b {Push 1, 2, 3 } ' Push add to top, so 3 is at top
Stack b {
While not empty {
Read k ' Read used to pop value to a variable
\\ number pop value in an expression
Print k, number, ' 3 2 1 1 2 3
}
Print
}
z=[] ' [] pop all values from current stack to a new stack, and return a pointer
Print z ' 2 1
z=Stack(a, z,a, z) ' merge stack objects, to a new one, preserve a and z
Print Len(z)
\\ empty a using a new object
a=stack
b=stack:=1,2,3
\\ z has two stack objects
z=stack:= a, b
Stack b { data 1000}
b=stack ' b point to a new stack
\\ we get pointer back
b=stackitem(z, 2)
Print stackitem(b, 4)=1000
</syntaxhighlight>

So now lets see the code:

<syntaxhighlight lang="m2000 interpreter">
Module CheckHistoryVariables {
Class History {
Private:
myvalue=stack
Public:
Group Count {
Value {
link parent myvalue to m
=Len(m)
}
}
Function CopyMe {
m=This
.myvalue<=stack(.myvalue)
=Group(m)
}
Group CopyValues {
Value {
link parent myvalue to m
=Stack(m)
}
}
Function Values (x as long) {
if x>=0 and x<=len(.myvalue) then =StackItem(.myvalue, x)
Else Error "Fault index"
}
Module Back {
if len(.myvalue)<2 then exit
Stack .myvalue {Drop}
}
Operator "++" {
Stack .myvalue {
Push stackitem()+1
}
}
Operator "--" {
Stack .myvalue {
Push stackitem()-1
}
}
Operator "+=" (x) {
Stack .myvalue {
Push stackitem()+x
} }
Operator "-=" (x) {
Stack .myvalue {
Push stackitem()-x
}
}
Operator "/=" (x){
if x==0 then error "division by zero"
Stack .myvalue {
Push stackitem()/x
}
}
Operator "*=" (x){
Stack .myvalue {
Push stackitem()*x
}
}
Value {
=StackItem(.myvalue)
}
Set {
Read x : Stack .myvalue { Push x}
}
Class:
Module History {
If Match("N") then Read x : Stack .myvalue { Push x}
}
}
N=History()
N=1
N=2
N=3
Print N, N.Values(2), N.Values(3), N.Count
\\ Get a copy of history
m=N.CopyValues
Print len(m)=3
\\ just show all
Print m ' 3 2 1
\\ or iterate from last to first
k=each(m, -1, 1)
While k {
Print Stackitem(k) \\ 1 NL 2 NL 3 (NL = new line)
}
N1=N.CopyMe()
N=5
N1=4
N=6
Print N
Print N1.Count=4, N.Count=5
Print N1, N
Print N.CopyValues ' 6 5 3 2 1
Print N1.CopyValues ' 4 3 2 1
Print N1<N
N=N+1
Print N.Count=6
Print N.CopyValues ' 6 5 3 2 1
Print "Go Back"
While N.Count>1 {
N.Back
Print N
}
N+=10
N*=2
Print N.CopyValues ' 22 11 1
}
CheckHistoryVariables

\\ for strings
Module CheckStringHistoryVariables {
Class History$ {
Private:
myvalue=stack
Public:
Group Count {
Value {
link parent myvalue to m
=Len(m)
}
}
Function CopyMe {
m=This
.myvalue<=stack(.myvalue)
=Group(m)
}
Group CopyValues {
Value {
link parent myvalue to m
=Stack(m)
}
}
Function Values$ (x as long) {
if x>=0 and x<=len(.myvalue) then =StackItem$(.myvalue, x)
Else Error "Fault index"
}
Module Back {
if len(.myvalue)<2 then exit
Stack .myvalue {Drop}
}
Operator "+=" (x$) {
Stack .myvalue {
Push stackitem$()+x$
} }
Value {
=StackItem$(.myvalue)
}
Set {
Read x$ : Stack .myvalue { Push x$}
}
Class:
Module History {
If Match("S") then Read x$ : Stack .myvalue { Push x$}
}
}
N$=History$("First")
N$="Second"
N$="Third"
Print N.Count=3
M=N.CopyValues
K=Each(M, -1, 1)
While K {
Print StackItem$(K)
}
N$+=" and this"
Print N.Count=4
Print N.CopyValues
N.Back
Print N.Count=3
Print N.CopyValues
Print N.Values$(2)="Second"
Input "New value:", N$
Print N$
Print N.Count=4
Print N.CopyValues
}
CheckStringHistoryVariables
</syntaxhighlight>

=={{header|Nim}}==
Nim doesn’t provide history variables, but it is easy to implement them.
As Nim is statically typed, we define history variable type in a generic way.

<syntaxhighlight lang="nim">type HistoryVar[T] = object
hist: seq[T]

func initHistoryVar[T](value: T = T.default): HistoryVar[T] =
## Initialize a history variable with given value.
result.hist.add value

func set(h: var HistoryVar; value: h.T) =
## Set the history variable to given value.
h.hist.add value

func get(h: HistoryVar): h.T =
## Return the current value of history variable.
h.hist[^1]

proc showHistory(h: HistoryVar) =
## Show the history starting from oldest values.
for i, value in h.hist:
echo i, ": ", value

func pop(h: var HistoryVar): h.T =
## Pop the current value and return it.
if h.hist.len > 1: h.hist.pop() else: h.hist[0]


when isMainModule:

var h = initHistoryVar[int]() # Initialized to 0.

echo "Assigning three values: 1, 2, 3"
h.set(1) # 0, 1
h.set(2) # 0, 1, 2
h.set(3) # 0, 1, 2, 3

echo "History (oldest values first):"
h.showHistory()

echo "Current value is ", h.get()

echo "Recall the three values:"
echo h.pop() # -> 3, last value removed.
echo h.pop() # -> 2, last value removed.
echo h.pop() # -> 1, last value removed.

echo "History (note that initial value can never be removed):"
h.showHistory()</syntaxhighlight>

{{out}}
<pre>Assigning three values: 1, 2, 3
History (oldest values first):
0: 0
1: 1
2: 2
3: 3
Current value is 3
Recall the three values:
3
2
1
History (note that initial value can never be removed):
0: 0</pre>

=={{header|Oberon-2}}==
<syntaxhighlight lang="oberon2">
MODULE HVar;
IMPORT Out, Conv;
TYPE
(* Generic Object *)
Object* = POINTER TO ObjectDesc;
ObjectDesc = RECORD
Show: PROCEDURE(o:Object);
AsString: PROCEDURE(o: Object; VAR str: ARRAY OF CHAR);
END;
(* Integers *)
Integer = POINTER TO IntegerDesc;
IntegerDesc = RECORD (ObjectDesc)
val: INTEGER;
END;
(* Chars *)
Char = POINTER TO CharDesc;
CharDesc = RECORD (ObjectDesc)
val: CHAR;
END;
Node = POINTER TO NodeDesc;
NodeDesc = RECORD
val: Object;
next: Node;
END;
(* History Variable *)
HVar* = POINTER TO HVarDesc;
HVarDesc = RECORD
first, last: Node;
size-: INTEGER;
END;
PROCEDURE CharAsString(o:Object; VAR dst: ARRAY OF CHAR);
BEGIN
IF LEN(dst) >= 2 THEN
dst[1] := 0X;
END;
dst[0] := o(Char)^.val
END CharAsString;
PROCEDURE IntAsString(o:Object; VAR dst: ARRAY OF CHAR);
BEGIN
Conv.ConvInt(o(Integer)^.val,dst);
END IntAsString;
PROCEDURE ShowInt(o:Object);
BEGIN
Out.Int(o(Integer)^.val,10);
END ShowInt;
PROCEDURE ShowChar(o:Object);
BEGIN
Out.Char(o(Char)^.val);
END ShowChar;
PROCEDURE BoxChar(val: CHAR): Char;
VAR
c: Char;
BEGIN
NEW(c);
c^.val := val;
c^.Show := ShowChar;
c^.AsString := CharAsString;
RETURN c;
END BoxChar;
PROCEDURE BoxInt(val:INTEGER): Integer;
VAR
i: Integer;
BEGIN
NEW(i);
i^.val := val;
i^.Show := ShowInt;
i^.AsString := IntAsString;
RETURN i;
END BoxInt;
PROCEDURE InitNode(): Node;
VAR
l: Node;
BEGIN
NEW(l);
l.val := NIL;
l.next := NIL;
RETURN l;
END InitNode;
PROCEDURE InitHVar(): HVar;
VAR
hv: HVar;
BEGIN
NEW(hv);
hv.first := NIL;
hv.last := NIL;
hv.size := 0;
RETURN hv;
END InitHVar;
PROCEDURE (v: HVar) Value(): Object;
BEGIN
RETURN v^.first^.val;
END Value;
PROCEDURE (v: HVar) Set(o: Object);
VAR
l: Node;
BEGIN
l := InitNode();
l^.val := o;
IF (v^.first = v^.last) & (v^.first = NIL) THEN
v^.first := l;
v^.last := l;
INC(v^.size);
ELSIF (v^.first = v^.last) & (v^.first # NIL) THEN
v^.first^.next := l;
v^.last := v^.first.next;
INC(v^.size);
ELSIF (v^.first # v^.last) THEN
v^.last^.next := l;
v^.last := l;
INC(v^.size);
END
END Set;
PROCEDURE (v: HVar) Undo(): Object;
VAR
o: Object;
BEGIN
IF (v^.first = v^.last) & (v^.first = NIL) THEN
o := NIL;
ELSIF (v^.first = v^.last) & (v^.first # NIL) THEN
o := v^.first^.val;
v^.first := NIL;
v^.last := NIL;
DEC(v^.size);
ELSE
o := v^.first^.val;
v^.first := v^.first^.next;
DEC(v^.size);
END;
RETURN o;
END Undo;
PROCEDURE (v: HVar) Print();
VAR
iter : Node;
BEGIN
iter := v.first;
WHILE(iter # NIL) DO
iter^.val^.Show(iter^.val);
iter := iter^.next;
END;
Out.Ln;
END Print;
PROCEDURE ShowVal(val: Object);
VAR
s: ARRAY 128 OF CHAR;
BEGIN
val^.AsString(val,s);
Out.String("> ");Out.String(s);Out.Ln;
END ShowVal;
VAR
history: HVar;
BEGIN
history := InitHVar();
history.Set(BoxChar(64X));
history.Set(BoxInt(10));
history.Set(BoxInt(15));
history.Set(BoxInt(20));
history.Print();
ShowVal(history.Undo());
ShowVal(history.Undo());
ShowVal(history.Undo());
END HVar.
</syntaxhighlight>

=={{header|OCaml}}==
The easiest solution is to use the Stack module coming with OCaml's standard library:
<syntaxhighlight lang="ocaml">
open Stack
(* The following line is only for convenience when typing code *)
module H = Stack

let show_entry e =
Printf.printf "History entry: %5d\n" e

let () =
let hs = H.create() in
H.push 111 hs ;
H.push 4 hs ;
H.push 42 hs ;
H.iter show_entry hs;
hs |> H.pop |> Printf.printf "%d\n";
hs |> H.pop |> Printf.printf "%d\n";
hs |> H.pop |> Printf.printf "%d\n"
</syntaxhighlight>

{{out}}
<pre>
History entry: 42
History entry: 4
History entry: 111
42
4
111
</pre>

=={{header|OxygenBasic}}==
Simple history class for fixed length types that do not contain volatile pointer members.
<syntaxhighlight lang="oxygenbasic">
'============
class History
'============

indexbase 0

string buf
sys ii,ld,pb

method constructor(sys n=1000, l=sizeof sys) {buf=nuls n*l : pb=strptr buf : ld=l : ii=0}
method destructor () {clear}
'
method setup(sys n=1000, l=sizeof sys) {buf=nuls n*l : pb=strptr buf : ld=l : ii=0}
method clear() {buf="" : pb=0 : ld=0 : ii=0}
method max (sys i) {if i>ii{ii=i}}
method count() as sys {return ii}
method size () as sys {return ld}
'
method get (any*p,i) {copy @p, pb+i*ld,ld } 'out
method add (any*p) {copy pb+ii*ld,@p,ld : ii++} 'in
method put (any*p,sys i) {copy pb+i*ld,@p,ld : max i} 'in
'
end class

'====
'TEST
'====

'this works for fixed length types

'it will not work for types containing
'volatile pointers. eg: string members

type vector double x,y,z

vector v

new History hv(1000,sizeof v) 'give number of records and variable size

sys i
for i=0 to 9
v<=i,i*10,i*100 'assign new values to vector
hv.add v 'add to history
next

string tab=chr(9) : cr=chr(13)+chr(10)
string pr="Data History of v" cr cr
pr+="n" tab "x" tab "y" tab "z" cr
vector sv
'
for i=hv.count()-1 to 0 step -1
hv.get sv,i
pr+=i tab sv.x tab sv.y tab sv.z cr
next

print pr 'result '9,90,900 : 8,80,800 ...

del hv
</syntaxhighlight>

=={{header|PARI/GP}}==
<syntaxhighlight lang="parigp">default(histsize, 1000) \\ or some other positive number to suit
1+7
sin(Pi)
2^100
\a1 \\ display history item #1, etc.
% \\ alternate syntax
%1 \\ alternate syntax
\a2
\a3
[%1, %2, %3] \\ or any other command using these values</syntaxhighlight>


=={{header|Protium}}==
=={{header|Peloton}}==
<lang protium>Turn history on <@ DEFHST>__on</@>
<syntaxhighlight lang="sgml">Turn history on <@ DEFHST>__on</@>
Notify Protium we are interested in the variable mv
Notify Protium we are interested in the variable mv
<@ DEFHST>mv</@>
<@ DEFHST>mv</@>
Line 105: Line 2,188:
Undo once: <@ ACTUNDVAR>mv</@><@ SAYVAR>mv</@>
Undo once: <@ ACTUNDVAR>mv</@><@ SAYVAR>mv</@>
Undo twice: <@ ACTUNDVAR>mv</@><@ SAYVAR>mv</@>
Undo twice: <@ ACTUNDVAR>mv</@><@ SAYVAR>mv</@>
Turn history off <@ DEFHST>__off</@></lang>
Turn history off <@ DEFHST>__off</@></syntaxhighlight>


Same code, Simplified Chinese dialect
Same code, Simplified Chinese dialect
<lang protium>Turn history on <# 定义变量史>__on</#>
<syntaxhighlight lang="sgml">Turn history on <# 定义变量史>__on</#>
Notify Protium we are interested in the variable mv
Notify Protium we are interested in the variable mv
<# 定义变量史>mv</#>
<# 定义变量史>mv</#>
Line 118: Line 2,201:
Undo once: <# 运行撤消变量>mv</#><# 显示变量>mv</#>
Undo once: <# 运行撤消变量>mv</#><# 显示变量>mv</#>
Undo twice: <# 运行撤消变量>mv</#><# 显示变量>mv</#>
Undo twice: <# 运行撤消变量>mv</#><# 显示变量>mv</#>
Turn history off <# 定义变量史>__off</#>
Turn history off <# 定义变量史>__off</#> </syntaxhighlight>
</lang>


{{out}}
Sample output
<pre>Turn history on
<pre>Turn history on
Notify Protium we are interested in the variable mv
Notify Protium we are interested in the variable mv
Line 133: Line 2,215:
Undo twice: first value
Undo twice: first value
Turn history off
Turn history off
</pre>

=={{header|Perl}}==
Implemented via tie (and what's the usefulness of this?)
<syntaxhighlight lang="perl">package History;

sub TIESCALAR {
my $cls = shift;
my $cur_val = shift;
return bless [];
}

sub FETCH {
return shift->[-1]
}

sub STORE {
my ($var, $val) = @_;
push @$var, $val;
return $val;
}

sub get(\$) { @{tied ${+shift}} }
sub on(\$) { tie ${+shift}, __PACKAGE__ }
sub off(\$) { untie ${+shift} }
sub undo(\$) { pop @{tied ${+shift}} }

package main;

my $x = 0;
History::on($x);

for ("a" .. "d") { $x = $_ }

print "History: @{[History::get($x)]}\n";

for (1 .. 3) {
print "undo $_, ";
History::undo($x);
print "current value: $x\n";
}

History::off($x);
print "\$x is: $x\n";</syntaxhighlight>
{{out}}<syntaxhighlight lang="text">History: a b c d
undo 1, current value: c
undo 2, current value: b
undo 3, current value: a
$x is: a</syntaxhighlight>

=={{header|Phix}}==
No native support, but trivial to implement.<br>
If you only need the history for a single variable, you can just do this, though it does not work under pwa/p2js:
<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (desktop/Phix only)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">history</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">type</span> <span style="color: #000000;">hvt</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">o</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">history</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">history</span><span style="color: #0000FF;">,</span><span style="color: #000000;">o</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">type</span>
<span style="color: #000000;">hvt</span> <span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span>
<span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">3</span>
<span style="color: #0000FF;">?{</span><span style="color: #008000;">"current"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">test</span><span style="color: #0000FF;">}</span>
<span style="color: #0000FF;">?{</span><span style="color: #008000;">"history"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">history</span><span style="color: #0000FF;">}</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
{"current",3}
{"history",{1,2,3}}
</pre>
Multiple history variables would require that routines must be invoked to create, update, and inspect them, and would be pwa/p2js compatible.<br>
Writing this as a separate reusable component (but omitting destroy/freelist handling for simplicity):
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- history.e</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">histories</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">global</span> <span style="color: #008080;">function</span> <span style="color: #000000;">new_history_id</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">histories</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">histories</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">v</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">histories</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">global</span> <span style="color: #008080;">procedure</span> <span style="color: #000000;">set_hv</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">hv</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">object</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">histories</span><span style="color: #0000FF;">[</span><span style="color: #000000;">hv</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">histories</span><span style="color: #0000FF;">[</span><span style="color: #000000;">hv</span><span style="color: #0000FF;">],</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">global</span> <span style="color: #008080;">function</span> <span style="color: #000000;">get_hv</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">hv</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">histories</span><span style="color: #0000FF;">[</span><span style="color: #000000;">hv</span><span style="color: #0000FF;">][$]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">global</span> <span style="color: #008080;">function</span> <span style="color: #000000;">get_hv_full_history</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">hv</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">histories</span><span style="color: #0000FF;">[</span><span style="color: #000000;">hv</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<!--</syntaxhighlight>-->
And use it like this
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">include</span> <span style="color: #000000;">history</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">test2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">new_history_id</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">set_hv</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">set_hv</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?{</span><span style="color: #008000;">"current"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">get_hv</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test2</span><span style="color: #0000FF;">)}</span>
<span style="color: #0000FF;">?{</span><span style="color: #008000;">"history"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">get_hv_full_history</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test2</span><span style="color: #0000FF;">)}</span>
<!--</syntaxhighlight>-->
Same output. Of course test2 does not ''have'' to be a constant, but it may help.

=={{header|PicoLisp}}==
<syntaxhighlight lang="picolisp">(de setH ("Var" Val)
(when (val "Var")
(with "Var"
(=: history (cons @ (: history))) ) )
(set "Var" Val) )

(de restoreH ("Var")
(set "Var" (pop (prop "Var" 'history))) )</syntaxhighlight>
Test:
<pre>: (setH 'A "Hello world")
-> "Hello world"

: (setH 'A '(a b c d))
-> (a b c d)

: (setH 'A 123)
-> 123

: A
-> 123

: (get 'A 'history)
-> ((a b c d) "Hello world")

: (restoreH 'A)
-> (a b c d)

: (restoreH 'A)
-> "Hello world"

: A
-> "Hello world"

: (restoreH 'A)
-> NIL</pre>

=={{header|PL/I}}==
<syntaxhighlight lang="pl/i">
declare t float controlled;

do i = 1 to 5; /* a loop to read in and save five values. */
allocate t; get (t);
end;

do while (allocation(t) > 0); /* a loop to retrieve the values. */
put (t); free t;
end;
</syntaxhighlight>

=={{header|PureBasic}}==
<syntaxhighlight lang="purebasic">; integer history variable

Structure historyint
List value.i()
EndStructure

Procedure SetInt (*var.historyint, val.i)
AddElement(*var\value())
If (ListSize(*var\value()) = 1)
*var\value() = 0
AddElement(*var\value())

EndIf
*var\value() = val
EndProcedure

Procedure ShowHistory (*var.historyint)
ForEach *var\value()
Debug *var\value()
Next
EndProcedure

Procedure UndoInt (*var.historyint)
If (ListSize(*var\value()) = 1)
ProcedureReturn
EndIf
DeleteElement(*var\value())
EndProcedure

;----------------------------------------------

Define x.historyint

For i = 0 To 3
setint(x, Random(50)+100 )
Next

Debug "x history:"
ShowHistory(x)

Debug ""

For i = 0 To 3
UndoInt(x)
Debug "undo, x = "+Str(x\value())
Next
</syntaxhighlight>

{{out}}
<pre style="overflow:scroll">
x history:
0
131
109
143
108

undo, x = 143
undo, x = 109
undo, x = 131
undo, x = 0
</pre>

=={{header|Python}}==

<syntaxhighlight lang="python">import sys

HIST = {}

def trace(frame, event, arg):
for name,val in frame.f_locals.items():
if name not in HIST:
HIST[name] = []
else:
if HIST[name][-1] is val:
continue
HIST[name].append(val)
return trace

def undo(name):
HIST[name].pop(-1)
return HIST[name][-1]

def main():
a = 10
a = 20

for i in range(5):
c = i

print "c:", c, "-> undo x3 ->",
c = undo('c')
c = undo('c')
c = undo('c')
print c
print 'HIST:', HIST

sys.settrace(trace)
main()</syntaxhighlight>
{{out}}<syntaxhighlight lang="text">c: 4 -> undo x3 -> 1
HIST: {'a': [10, 20], 'i': [0, 1, 2, 3, 4], 'c': [0, 1], 'name': ['c']}</syntaxhighlight>


=={{header|Quackery}}==

Quackery does not have variables, it has ancillary stacks that can serve, amongst their uses, as variables and as history variables. Given an ancillary stack <code>x</code>, the following Quackery words are relevant.

*<code>x put</code> moves an item from the data stack to the ancillary stack <code>x</code>.
*<code>x take</code> moves an item from the ancillary stack <code>x</code> to the data stack.
*<code>x share</code> copies the top of the ancillary stack <code>x</code> to the data stack.
*<code>x replace</code> replaces the top item on the ancillary stack <code>x</code> with the item on top of the data stack.
*<code>x behead drop</code> leaves a copy of the ancillary stack <code>x</code> on the data stack as a nest (dynamic array).


The requirements of this task demonstrated as a dialogue in the Quackery shell.

<pre>/O> [ stack ] is x
... 3 x put
... 4 x put
... 5 x put
... x behead drop echo cr
... x take echo cr
... x take echo cr
... x take echo cr
...
[ 3 4 5 ]
5
4
3
</pre>


=={{header|Racket}}==

Racket does not come with history variables, but they can be provided as a library as follows:

<syntaxhighlight lang="racket">
#lang racket

(require rackunit)

(struct hvar (current history) #:mutable)

(define (make-hvar v) (hvar v empty))

(define (hvar-set! hv new)
(match-define (hvar cur hist) hv)
(set-hvar-history! hv (cons cur hist))
(set-hvar-current! hv new))

(define (hvar-undo! hv)
(match-define (hvar cur (cons old hist)) hv)
(set-hvar-current! hv old)
(set-hvar-history! hv hist))

;; unit tests
(define hv (make-hvar 0))
(hvar-set! hv 1)
(check-equal? (hvar-current hv) 1)
(hvar-set! hv 2)
(hvar-set! hv 3)
(check-equal? (hvar-history hv) '(2 1 0))
(hvar-undo! hv)
(hvar-undo! hv)
(hvar-undo! hv)
(check-equal? (hvar-current hv) 0)
</syntaxhighlight>

=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2018.03}}
<syntaxhighlight lang="raku" line>class HistoryVar {
has @.history;
has $!var handles <Str gist FETCH Numeric>;
method STORE($val) is rw {
push @.history, [now, $!var];
$!var = $val;
}
}

my \foo = HistoryVar.new;

foo = 1;
foo = 2;
foo += 3;
foo = 42;

.say for foo.history;
say "Current value: {foo}";</syntaxhighlight>
{{out}}
<pre>[Instant:1523396079.685629 (Any)]
[Instant:1523396079.686844 1]
[Instant:1523396079.687130 2]
[Instant:1523396079.687302 5]
Current value: 42
</pre>

=={{header|REXX}}==
===Version 1===
The REXX language doesn't support histories, but can be coded with little trouble.
<br><br>The history list part of the &nbsp' '''varSet''' &nbsp; subroutine could be separated into its
<br>own if you wanted to keep the subroutine's function pure.
<syntaxhighlight lang="rexx">/*REXX program demonstrates a method to track history of assignments to a REXX variable.*/
varSet!.=0 /*initialize the all of the VARSET!'s. */
call varSet 'fluid',min(0,-5/2,-1) ; say 'fluid=' fluid
call varSet 'fluid',3.14159 ; say 'fluid=' fluid
call varSet 'fluid',' Santa Claus' ; say 'fluid=' fluid
call varSet 'fluid',,999
say 'There were' result "assignments (sets) for the FLUID variable."
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
varSet: arg ?x; parse arg ?z, ?v, ?L /*obtain varName, value, optional─List.*/
if ?L=='' then do /*not la ist, so set the X variable.*/
?_=varSet!.0.?x+1 /*bump the history count (# of SETs). */
varSet!.0.?x=?_ /* ... and store it in the "database"*/
varSet!.?_.?x=?v /* ... and store the SET value. */
call value(?x),?v /*now, set the real X variable. */
return ?v /*also, return the value for function. */
end
say /*show a blank line for readability. */
do ?j=1 to ?L while ?j<=varSet!.0.?x /*display the list of "set" history. */
say 'history entry' ?j "for var" ?z":" varSet!.?J.?x
end /*?j*/
return ?j-1 /*return the number of assignments. */</syntaxhighlight>
'''output'''
<pre>
fluid= -2.5
fluid= 3.14159
fluid= Santa Claus

history entry 1 for var fluid: -2.5
history entry 2 for var fluid: 3.14159
history entry 3 for var fluid: Santa Claus
There were 3 assignments (sets) for the FLUID variable.
</pre>

===Version 2===
<syntaxhighlight lang="rexx">
/* REXX ***************************************************************
* Demonstrate how the history of assignments can be kept and shown
* 13.07.2012 Walter Pachl Rewrite of Version 1 for (my) readability
* varset.i.varu contains the ith value assigned to var
* varset.0.varu contains the number of assignments so far
**********************************************************************/
varset.=0 /*initialize the assignment count */

call varset 'fluid',min(0,-5/2,-1) ; say 'fluid=' fluid
call varset 'fluid',3.14159 ; say 'fluid=' fluid
call varset 'fluid',3.14159 ; say 'fluid=' fluid
call varset 'fluid',' Santa Claus' ; say 'fluid=' fluid
call varset 'FLUID',' Easter Rabbit' ; say 'fluid=' fluid

say 'There were' varset('fluid',,'L'),
'assignments (sets) for the FLUID variable.'
exit

varset: Procedure Expose varset.
/**********************************************************************
* record values assigned to var (=varu as Rexx is case insensitive)
* Invoke with list<>'' to list the sequence of assigned values
* and return the number of assignments made (using this routine)
**********************************************************************/
Parse Upper Arg varu /* name of variable in uppercase */
Parse arg var,value,list /*varName, value, optional-List. */

if list='' then do /*not list, so set the X variable*/
z=varset.0.varu+1 /*bump the history count (SETs). */
varset.z.varu=value /* ... and store it in "database"*/
varset.0.varu=z /*the new history count */
call value var,value /*now assign the value to var */
end
else Do
Say '' /*show blank line for readability*/
do i=1 to varset.0.varu /*list the assignment history */
say 'history entry' i "for var" var":" varset.i.varu
end
end
Return varset.0.varu /*return the number of assignments. */
</syntaxhighlight>

=={{header|Ruby}}==
This uses trace_var, which only works for global variables:
<syntaxhighlight lang="ruby">foo_hist = []
trace_var(:$foo){|v| foo_hist.unshift(v)}

$foo = "apple"
$foo = "pear"
$foo = "banana"

p foo_hist # => ["banana", "pear", "apple"]
</syntaxhighlight>

=={{header|Rust}}==
<syntaxhighlight lang="rust">#[derive(Clone, Debug)]
struct HVar<T> {
history: Vec<T>,
current: T,
}

impl<T> HVar<T> {
fn new(val: T) -> Self {
HVar {
history: Vec::new(),
current: val,
}
}

fn get(&self) -> &T {
&self.current
}

fn set(&mut self, val: T) {
self.history.push(std::mem::replace(&mut self.current, val));
}

fn history(&self) -> (&[T], &T) {
(&self.history, &self.current)
}

fn revert(&mut self) -> Option<T> {
self.history
.pop()
.map(|val| std::mem::replace(&mut self.current, val))
}
}

fn main() {
let mut var = HVar::new(0);
var.set(1);
var.set(2);
println!("{:?}", var.history());
println!("{:?}", var.revert());
println!("{:?}", var.revert());
println!("{:?}", var.revert());
println!("{:?}", var.get());
}</syntaxhighlight>
{{out}}
<pre>([0, 1], 2)
Some(2)
Some(1)
None
0</pre>

=={{header|Scala}}==
Scala doesn't have a native support for history variables, but it's quite easy to implement them. The following class uses same conventions as ML's mutable reference cells. (i.e. <code>!</code> as accessor, and <code>:=</code> as mutator.)
<syntaxhighlight lang="scala">class HVar[A](initialValue: A) extends Proxy {
override def self = !this
override def toString = "HVar(" + !this + ")"
def history = _history

private var _history = List(initialValue)
def unary_! = _history.head
def :=(newValue: A): Unit = {
_history = newValue :: _history
}
def modify(f: A => A): Unit = {
_history = f(!this) :: _history
}
def undo: A = {
val v = !this
_history = _history.tail
v
}
}</syntaxhighlight>
Usage:
<syntaxhighlight lang="scala">scala> val h = new HVar(3)
h: HVar[Int] = HVar(3)

scala> h := 11

scala> h := 90

scala> !h
res32: Int = 90

scala> h.history
res33: List[Int] = List(90, 11, 3)

scala> h.undo
res34: Int = 90

scala> h.undo
res35: Int = 11

scala> h.undo
res36: Int = 3</syntaxhighlight>

=={{header|SenseTalk}}==
SenseTalk does not have native support for history variables, but here is a simple object that can be instantiated to provide a history:
<syntaxhighlight lang="sensetalk">// HistoryVariable.script
properties
history: [], -- a list of all historical values
asTextFormat:"[[the last item of my history]]" -- always display the last value
end properties

to set newValue
push newValue nested into my history
end set

to rollback
pop my history
return it
end rollback
</syntaxhighlight>
Here is an example how this could be used (note that variables in SenseTalk may hold any type of value):
<syntaxhighlight lang="sensetalk">set x to be a new HistoryVariable

tell x to set "Hello"
put "x is now" && x -- display the current value

tell x to set 88
put "x is now" && x

tell x to set "World"
put "x is now" && x

put "History of x:" && x's history -- non-destructively display the history

tell x to set [9,6,3] -- set it to a list
put "x is now" && x

put "History of x:" && the history of x

put "Rolling back:" && x.rollback -- remove the last value
put "After rollback, x is now" && x
</syntaxhighlight>
{{out}}
<pre>
x is now Hello
x is now 88
x is now World
History of x: ["Hello",88,"World"]
x is now [9,6,3]
History of x: ["Hello",88,"World",[9,6,3]]
Rolling back: [9,6,3]
After rollback, x is now World
</pre>

=={{header|Sidef}}==
Implemented as a class:
<syntaxhighlight lang="ruby">class HistoryVar(v) {

has history = []
has variable = v

method ≔(value) {
history << variable
variable = value
}

method to_s {
"#{variable}"
}

method AUTOLOAD(_, name, *args) {
variable.(name)(args...)
}
}

var foo = HistoryVar(0)

foo ≔ 1
foo ≔ 2
foo ≔ foo+3
foo ≔ 42

say "History: #{foo.history}"
say "Current value: #{foo}"</syntaxhighlight>
{{out}}
<pre>
History: [0, 1, 2, 5]
Current value: 42
</pre>

=={{header|Smalltalk}}==
Smalltalk doesn't have native support for history variables. It could be implemented using (implementation dependent) tracing facilities, or by changing the code generator (which is part of the library and open for change).
The following implementation is portable and in the spirit of the Lisp implementation above, and defines a new "assignment operator":
<syntaxhighlight lang="smalltalk">Object subclass:'HVar'
instanceVariableNames:'values'
classVariableNames:''
poolDictionaries:''
category:'example'.
!

!HVar methodsFor:'accessing'!

<-- value
(values ifNil:[values := OrderedCollection new]) add:value.
^ value
!

value
^ values last
!

undo
values removeLast.
!

history
^ history
! !

|x|

x := HVar new.
x <-- 1.
x value.
x <-- 2.
x <-- (x value + 1).
x value.
x history.
</syntaxhighlight>

=={{header|Swift}}==
Swift does not support history variables. However, you can add a watcher that can track when the variable will change.
<syntaxhighlight lang="swift">var historyOfHistory = [Int]()
var history:Int = 0 {
willSet {
historyOfHistory.append(history)
}
}

history = 2
history = 3
history = 4
println(historyOfHistory)
</syntaxhighlight>

another approach, using generics:
plug this code into a Playground to see the output
{{works with|Swift|2.x+}}
<syntaxhighlight lang="swift">

struct History <T> {
private var _history = [T]()
var history : [T] {
return _history
}
var now : T {
return history.last!
}
init(_ firstValue:T) {
_history = [firstValue]
}
mutating func set(newValue:T) {
_history.append(newValue)
}
mutating func undo() -> T {
guard _history.count > 1 else { return _history.first! }
_history.removeLast()
return _history.last!
}
}

var h = History("First")
h.set("Next")
h.set("Then")
h.set("Finally")
h.history // output ["First", "Next", "Then", "Finally"]

h.now // outputs "Finally"
h.undo() // outputs "Then"
h.undo() // outputs "Next"
h.undo() // outputs "First"
h.undo() // outputs "First", since it can't roll back any further
h.undo() // outputs "First"

</syntaxhighlight>

=={{header|Tcl}}==
Though Tcl's variables don't have history by default, it can be added easily through the use of traces:
<syntaxhighlight lang="tcl"># Define the history machinery
proc histvar {varName operation} {
upvar 1 $varName v ___history($varName) history
switch -- $operation {
start {
set history {}
if {[info exist v]} {
lappend history $v
}
trace add variable v write [list histvar.write $varName]
trace add variable v read [list histvar.read $varName]
}
list {
return $history
}
undo {
set history [lrange $history 0 end-1]
}
stop {
unset history
trace remove variable v write [list histvar.write $varName]
trace remove variable v read [list histvar.read $varName]
}
}
}
proc histvar.write {key varName args} {
upvar 1 $varName v ___history($key) history
lappend history $v
}
proc histvar.read {key varName args} {
upvar 1 $varName v ___history($key) history
set v [lindex $history end]
}</syntaxhighlight>
Demonstrating how to use it:
<syntaxhighlight lang="tcl"># Enable history for foo
histvar foo start
set foo {a b c d}
set foo 123
set foo "quick brown fox"
puts $foo
puts foo-history=[join [histvar foo list] ", "]
puts $foo
histvar foo undo
puts $foo
histvar foo undo
puts $foo
histvar foo stop</syntaxhighlight>
{{out}}
<pre>
quick brown fox
foo-history=a b c d, 123, quick brown fox
quick brown fox
123
a b c d
</pre>

=={{header|Wren}}==
{{trans|Kotlin}}
Not built in but we can soon make a suitable class.
<syntaxhighlight lang="wren">class HistoryVariable {
construct new(initValue) {
_history = [initValue]
}

currentValue { _history[-1] }
currentValue=(newValue) { _history.add(newValue) }

showHistory() {
System.print("The variable's history, oldest values first, is:")
for (item in _history) System.print(item)
}
}

var v = HistoryVariable.new(1)
v.currentValue = 2
v.currentValue = 3
v.showHistory()
System.print("\nCurrent value is %(v.currentValue)")</syntaxhighlight>

{{out}}
<pre>
The variable's history, oldest values first, is:
1
2
3

Current value is 3
</pre>

=={{header|zkl}}==
No native support, here is a something that can be done with a class:
<syntaxhighlight lang="zkl">class HistoryVar{
var [private] _v, _history=List(), maxSz;
fcn init(v,maxEntries=3){ maxSz=maxEntries; set(v) }
fcn set(v){
_v=v; _history.append(T(Time.Clock.time,v));
if(_history.len()>maxSz) _history.del(0);
self
}
fcn get(n=0){ // look back into history
z:=_history.len();
n=(if(n>=z) 0 else z-n-1);
_history[n][1]
}
var [proxy] v=fcn{ _v };
var [proxy] history=
fcn{ _history.pump(List,fcn([(t,v)]){ T(Time.Date.ctime(t),v) }) };
fcn __opAdd(x){ set(_v + x); self }
}</syntaxhighlight>
<syntaxhighlight lang="zkl">hv:=HistoryVar(123);
hv+4;
hv.set("Shuttle prepared for liftoff");
hv+": orbit achived";
hv.history.concat("\n").println();
hv.get(3).println("<-- value two changes ago");</syntaxhighlight>
{{out}}
<pre>
L("Thu Oct 13 13:48:37 2016",127)
L("Thu Oct 13 13:48:37 2016","Shuttle prepared for liftoff")
L("Thu Oct 13 13:48:37 2016","Shuttle prepared for liftoff: orbit achived")
127<-- value two changes ago
</pre>
</pre>


Line 142: Line 3,085:
{{omit from|C|No native support,but a debugger may keep track}}
{{omit from|C|No native support,but a debugger may keep track}}
{{omit from|C++|No native support,but a debugger may keep track}}
{{omit from|C++|No native support,but a debugger may keep track}}
{{omit from|GUISS}}
{{omit from|Locomotive Basic}}
{{omit from|Locomotive Basic}}
{{omit from|Lotus 123 Macro Scripting}}
{{omit from|Lotus 123 Macro Scripting}}
{{omit from|Lua}}
{{omit from|Lua}}
{{omit from|ML/I}}
{{omit from|UNIX Shell}}
{{omit from|UNIX Shell}}
{{omit from|Visual Basic|No native support,but a debugger may keep track}}
{{omit from|Visual Basic|No native support,but a debugger may keep track}}
{{omit from|ZX Spectrum Basic}}
{{omit from|ZX Spectrum Basic}}
{{omit from|Déjà Vu}}

Latest revision as of 11:15, 25 January 2024

Task
History variables
You are encouraged to solve this task according to the task description, using any language you may know.

Storing the history of objects in a program is a common task. Maintaining the history of an object in a program has traditionally required programmers either to write specific code for handling the historical data, or to use a library which supports history logging.

History variables are variables in a programming language which store not only their current value, but also the values they have contained in the past. Some existing languages do provide support for history variables. However these languages typically have many limits and restrictions on use of history variables.

[http://www.bod.com/index.php?id=3435&objk_id=148050 "History Variables: The Semantics, Formal Correctness, and Implementation of History Variables in an Imperative Programming Language" by Mallon and Takaoka]

Concept also discussed on LtU and Patents.com.

Task

Demonstrate History variable support:

  • enable history variable support (if needed)
  • define a history variable
  • assign three values
  • non-destructively display the history
  • recall the three values.


For extra points, if the language of choice does not support history variables, demonstrate how this might be implemented.

68000 Assembly

68000 Assembly doesn't support history variables natively. They can be implemented using a stack system. The 68000 can use push/pop commands on any address register, not just the hardware stack pointer.

HistoryVar equ $100200   ;assume this is work ram.

LEA HistoryVar+4,A0
MOVE.L #$11223344,D0
MOVE.L D0,-(A0)   ;store the 32-bit value #$11223344 starting at $100200
MOVE.L #$55667788,D0
MOVE.L D0,-(A0)   ;store the 32-bit value #$5566788 at $1001FC
MOVE.L #$AABBCCDD,D0
MOVE.L D0,-(A0)   ;store the 32-bit value #$AABBCCDD at $1001F8

;display the history
LEA HistoryVar,A0
MOVE.L (A0),D0        ;load #$11223344 into D0
MOVE.L (-4,A0),D1     ;load #$55667788 into D1
MOVE.L (-8,A0),D2     ;load #$AABBCCDD into D2

jsr PrintHex32        ;unimplemented routine that prints D0 as a 32-bit hex number
mov D1,D0
jsr PrintHex32
mov D2,D0
jsr PrintHex32

Whether this constitutes a single variable at this point is debatable, because at a hardware level anything you write to a memory address permanently erases what was there, with no way to get it back unless you saved it somewhere else. So storing three values at the same memory location won't maintain the history.

Ada

Ada does not natively support history variables -- we have to implement them.

Furthermore, Ada is a strongly typed language -- that means, we would need to write a history variable type for every basic item type. Instead, we write a single generic package "History_Variables" that works for any item type.


Generic Package "History_Variables"

Specification:

private with Ada.Containers.Indefinite_Vectors;
generic
   type Item_Type (<>) is private;
package History_Variables is

   type Variable is tagged limited private;

   -- set and get current value
   procedure Set(V: in out Variable; Item: Item_Type);
   function Get(V: Variable) return Item_Type;

   -- number of items in history (including the current one)
   function Defined(V: Variable) return Natural;

   -- non-destructively search for old values
   function Peek(V: Variable; Generation: Natural := 1) return Item_Type;
   -- V.Peek(0) returns current value; V.Peek(1) the previous value, etc.
   -- when calling V.Peek(i), i must be in 0 .. V.Defined-1, else Constraint_Error is raised

   -- destructively restore previous value
   procedure Undo(V: in out Variable);
   -- old V.Peek(0) is forgotten, old V.Peek(i) is new V.Peek(i-1), etc.
   -- accordingly, V.Defined decrements by 1
   -- special case: if V.Defined=0 then V.Undo does not change V

private
   package Vectors is new Ada.Containers.Indefinite_Vectors
     (Index_Type   => Positive,
      Element_Type => Item_Type);

   type Variable is tagged limited record
      History: Vectors.Vector;
   end record;
end History_Variables;

The implementation of "History_Variables":

package body History_Variables is

   -- set and get
   procedure Set(V: in out Variable; Item: Item_Type) is
   begin
      V.History.Prepend(Item);
   end Set;

   function Get(V: Variable) return Item_Type is
   begin
      return V.History.First_Element;
   end Get;

   -- number of items in history (including the current one)
   function Defined(V: Variable) return Natural is
   begin
      return (1 + V.History.Last_Index) - V.History.First_Index;
   end Defined;

   -- non-destructively search
   function Peek(V: Variable; Generation: Natural := 1) return Item_Type is
      Index: Positive  := V.History.First_Index + Generation;
   begin
      if Index > V.History.Last_Index then
         raise Constraint_Error;
      end if;
      return V.History.Element(Index);
   end Peek;

   procedure  Undo(V: in out Variable) is
   begin
      V.History.Delete_First;
   end Undo;

end History_Variables;


Sample 1: The History of an Integer Variable

with Ada.Text_IO, History_Variables;

procedure Test_History is

   package Int_With_Hist is new History_Variables(Integer);

   -- define a history variable
   I: Int_With_Hist.Variable;

   Sum: Integer := 0;

begin

   -- assign three values
   I.Set(3);
   I.Set(I.Get + 4);
   I.Set(9);

   -- non-destructively display the history
   for N in reverse 0 .. I.Defined-1 loop
      Ada.Text_IO.Put(Integer'Image(I.Peek(N)));
   end loop;
   Ada.Text_IO.New_Line;

   -- recall the three values
   while I.Defined > 0 loop
      Sum := Sum + I.Get;
      I.Undo;
   end loop;
   Ada.Text_IO.Put_Line(Integer'Image(Sum));

end Test_History;
Output:
 3 7 9
 19


Sample 2: The History of a String

with Ada.Text_IO, History_Variables;

procedure Test_History is

   package Str_With_Hist is new History_Variables(String);

   -- define a history variable
   S: Str_With_Hist.Variable;

   Sum: Integer := 0;

begin

   -- assign three values
   S.Set("one");
   S.Set(S.Get & S.Get); --"oneone"
   S.Set("three");

   -- non-destructively display the history
   for N in reverse 0 .. S.Defined-1 loop
      Ada.Text_IO.Put(S.Peek(Generation => N) &" ");
   end loop;
   Ada.Text_IO.New_Line;

   -- recall the three values
   while S.Defined > 0 loop
      Sum := Sum + S.Get'Length;
      S.Undo;
   end loop;
   Ada.Text_IO.Put_Line(Integer'Image(Sum));

end Test_History;
Output:
one oneone three 
 14

ALGOL W

Algol W does not have history variables as standard, as with other languages here, we can add them using a simple linked list.
As Algol W does not have generic types, a separate history variable type would be required for each type of variable.

begin
    % implements integer history variables                                 %
    % similar history types could be defined for other types of variable   %
    record HInteger ( integer iValue; reference(HInteger) iPrev );
    % sets the latest value of hv to n                                     %
    procedure setIhv ( reference(HInteger) value result hv; integer value n ) ; hv := HInteger( n, hv );
    % declare an integer history variable                                  %
    reference(HInteger) hv;
    % initialise the history to a null value                               %
    hv := null;
    % assign three values                                                  %
    setIhv( hv, 1 );
    setIhv( hv, 2 );
    setIhv( hv, 3 );
    % show the history of hv                                               %
    begin
        reference(HInteger) h;
        write( "hv history: " );
        h := hv;
        while h not = null do begin
            writeon( i_w := 3, s_w := 0, iValue(h), " " );
            h := iPrev(h)
        end while_h_ne_null
    end;
    % remove the values from hv, summing them as in the Ada sample         %
    begin
        integer s;
        s := 0;
        while hv not = null do begin
            s  := s + iValue(hv);
            hv := iPrev(hv)
        end while_hv_ne_null ;
        write( "Sum of the historic values: ", s )
    end
end.
Output:
hv history:   3   2   1
Sum of the historic values:              6

Arturo

define :history [][
    init: [
        this\record: @[0]
    ]
]
assign: function [historyVar,newValue][
    historyVar\record: historyVar\record ++ newValue
]

alias.infix {'-->} 'assign

records: function [historyVar][
    historyVar\record
]

retrieve: function [historyVar][
    result: last historyVar\record
    historyVar\record: chop historyVar\record
    return result
]

current: function [historyVar][
    return last historyVar\record
]

do [
    h: to :history []

    print "Assigning three values: 1, 2, 3..."
    h --> 1
    h --> 2
    h --> 3

    print "\nHistory (oldest values first):"
    print [">" records h]

    print ["\nCurrent value is:" current h]

    print "\nRecalling the three values..."
    loop 1..3 'x ->
        print ["- Recalled:" retrieve h]

    print "\nHistory:"
    print [">" records h]
]
Output:
Assigning three values: 1, 2, 3...

History (oldest values first):
> [0 1 2 3] 

Current value is: 3 

Recalling the three values...
- Recalled: 3 
- Recalled: 2 
- Recalled: 1 

History:
> [0] 

AspectJ

AspectJ implementation for Java 7. Type of the history variable (Java class):

public class HistoryVariable
{
    private Object value;

    public HistoryVariable(Object v)
    {
        value = v;
    }

    public void update(Object v)
    {
        value = v;
    }

    public Object undo()
    {
        return value;
    }

    @Override
    public String toString()
    {
        return value.toString();
    }

    public void dispose()
    {
    }
}

Aspect (HistoryHandling.aj):

import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

public privileged aspect HistoryHandling
{
    before() : execution(HistoryVariable.new(..))
    {
        history.put((HistoryVariable) thisJoinPoint.getTarget(), new LinkedList<>());
    }

    after() : execution(void HistoryVariable.dispose())
    {
        history.remove(thisJoinPoint.getTarget());
    }

    before(Object v) : execution(void HistoryVariable.update(Object)) && args(v)
    {
        final HistoryVariable hv = (HistoryVariable) thisJoinPoint.getThis();
        history.get(hv).add(hv.value);
    }

    after() : execution(Object HistoryVariable.undo())
    {
        final HistoryVariable hv = (HistoryVariable) thisJoinPoint.getThis();
        final Deque<Object> q = history.get(hv);
        if (!q.isEmpty())
            hv.value = q.pollLast();
    }

    String around() : this(HistoryVariable) && execution(String toString())
    {
        final HistoryVariable hv = (HistoryVariable) thisJoinPoint.getThis();
        final Deque<Object> q = history.get(hv);
        if (q == null)
            return "<disposed>";
        else
            return "current: "+ hv.value + ", previous: " + q.toString();
    }

    private Map<HistoryVariable, Deque<Object>> history = new HashMap<>();
}

Usage:

public final class Main
{
    public static void main(final String[] args)
    {
        HistoryVariable hv = new HistoryVariable("a");
        hv.update(90);
        hv.update(12.1D);
        System.out.println(hv.toString());
        System.out.println(hv.undo());
        System.out.println(hv.undo());
        System.out.println(hv.undo());
        System.out.println(hv.undo());
        System.out.println(hv.toString());
        hv.dispose();
        System.out.println(hv.toString());
    }
}
Output:
current: 12.1, previous: [a, 90]
12.1
90
a
a
current: a, previous: []
<disposed>

AutoHotkey

AutoHotkey records a history of your keypresses, but not your variables. The closest you can come is with a class:

Works with: AutoHotkey 1.1
HV := new HistoryVariable
HV.var := 1
HV.var := 2
HV.var := "Latest value"
Msgbox % HV.var "`n" HV[2] "`n" HV[3]

class HistoryVariable {
	__Set(aName, aValue) {
		this.Insert(1,aValue)
		Return aValue
	}
	__Get(aName) {
		Return this[1]
	}
}

C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace History
{
    class Program
    {
        static void Main(string[] args)
        {
            var h = new HistoryObject();
            h.Value = 5;
            h.Value = "foo";
            h.Value += "bar";

            var history = h.ToArray();

            for (int i = 0; i < history.Length; i++)
            {
                Console.Write("{0}{1}", history[i], ((i >= history.Length - 1) ? "\n" : " <- "));
            }

            h.Undo();
            h.Undo();
            h.Undo();

            Console.WriteLine(h.Value);
        }

        private class HistoryObject : IEnumerable<object>
        {
            public HistoryObject()
            {
                _history = new Stack<object>(); // Initiates the history stack.
            }

            public object Value
            {
                get // Returns the top value from the history if there is one. Otherwise null.
                {
                    if (_history.Count > 0)
                        return _history.Peek();
                    return null;
                }
                set { _history.Push(value); } // Adds the specified value to the history.
            }

            public void Undo()
            {
                if (_history.Count > 0)
                    _history.Pop(); // Removes the current value from the history.
            }

            // History stack that will hold all previous values of the object.
            private readonly Stack<object> _history;

            public IEnumerator<object> GetEnumerator()
            {
                return _history.GetEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }
    }
}
Output:
foobar <- foo <- 5

C++

C++ does not have history variables, but they can easily by implemented with a generic class.

#include <deque>
#include <iostream>
#include <string>

template <typename T>
class with_history {
public:
	with_history(const T& element) {
		history.push_front(element);
	}

	T get() {
		return history.front();
	}

	void set(const T& element) {
		history.push_front(element);
	}

	std::deque<T> get_history() {
		return std::deque<T>(history);
	}

	T rollback() {
		if ( history.size() > 1 ) {
			history.pop_front();
		}
		return history.front();
	}

private:
	std::deque<T> history;
};

int main() {
	with_history<double> number(1.2345);
	std::cout << "Current value of number: " << number.get() << std::endl;

	number.set(3.4567);
	number.set(5.6789);

	std::cout << "Historical values of number: ";
	for ( const double& value : number.get_history() ) {
		std::cout << value << "  ";
	}
	std::cout << std::endl << std::endl;

	with_history<std::string> word("Goodbye");
	word.set("Farewell");
	word.set("Hello");

	std::cout << word.get() << std::endl;
	word.rollback();
	std::cout << word.get() << std::endl;
	word.rollback();
	std::cout << word.get() << std::endl;
	word.rollback();
	std::cout << word.get() << std::endl;
	word.rollback();
}
Output:
Current value of number: 1.2345
Historical values of number: 5.6789  3.4567  1.2345  

Hello
Farewell
Goodbye
Goodbye

Clojure

Clojure does not have history variables, but it can be accomplished via a watcher function that can track changes on a variable.

(def a (ref 0))
(def a-history (atom [@a])) ; define a history vector to act as a stack for changes on variable a
(add-watch a :hist (fn [key ref old new] (swap! a-history conj new)))
Sample Output:
user=> (dosync (ref-set a 1))
1
user=> (dosync (ref-set a 2))
2
user=> (dosync (ref-set a 3))
3
user=> @a-history
[0 1 2 3]
user=> (dotimes [n 3] (println (peek @a-history)) (swap! a-history pop))
3
2
1
nil
user=> @a-history
[0]

Common Lisp

In Lisp the list is a natural and simple data structure for representing variables with history. By adding some simple macros we can make a small DSL that hides the list and makes it look like a history variable is it's own special thing.

(defmacro make-hvar (value) 
  `(list ,value))

(defmacro get-hvar (hvar)
  `(car ,hvar))

(defmacro set-hvar (hvar value)
  `(push ,value ,hvar))

;; Make sure that setf macro can be used
(defsetf get-hvar set-hvar)

(defmacro undo-hvar (hvar)
  `(pop ,hvar))

(let ((v (make-hvar 1)))
  (format t "Initial value = ~a~%" (get-hvar v))
  (set-hvar v 2)
  (setf (get-hvar v) 3) ;; Alternative using setf
  (format t "Current value = ~a~%" (get-hvar v))
  (undo-hvar v)
  (undo-hvar v)
  (format t "Restored value = ~a~%" (get-hvar v)))
Output:
Initial value = 1
Current value = 3
Restored value = 1

D

D does not have history variables. The following implementation provides a generic HistoryVariable that protects the historical values by defining them as 'const'.

import std.stdio, std.array, std.string, std.datetime, std.traits;

/// A history variable.
struct HistoryVariable(T) {
    /// A value in a point in time.
    static struct HistoryValue {
        SysTime time;
        T value;

        // Alternative to the more common toString.
        //void toString(scope void delegate(string) output) const {
        void toString(scope void delegate(const(char)[]) output)const {
            output(format("%s; %s", time, value));
        }
    }

    const(HistoryValue)[] values;

    private void addValue(T value) {
        values ~= HistoryValue(Clock.currTime(), value);
    }

    void opAssign(T value) {
        addValue(value);
    }

    @property T currentValue() const pure nothrow {
        return values.back.value;
    }

    alias currentValue this;

    @property auto history() const pure nothrow {
        return values;
    }

    /**
    Demonstrating D's compile-time reflection features. The member
    functions that are in this 'static if' block would be added for
    types T that are arrays (including strings). */
    static if (isArray!T) {
        // Append-with-assign operator.
        void opOpAssign(string op : "~")(T element) {
            addValue(currentValue ~ element);
        }

        // Similar implementation for other array operators...
    }
}

void main() {
    HistoryVariable!int x;
    x = 1;
    x = 2;
    x = 3;
    writefln("%(%s\n%)\n", x.history);

    HistoryVariable!string s;
    s = "hello";
    s ~= " world";
    s = "goodby";
    writefln("%(%s\n%)", s.history);
}
Sample Output:
2013-Jan-19 23:04:55.1660302; 1
2013-Jan-19 23:04:55.1660407; 2
2013-Jan-19 23:04:55.1660424; 3

2013-Jan-19 23:04:55.1662551; hello
2013-Jan-19 23:04:55.1662581; hello world
2013-Jan-19 23:04:55.1662596; goodby

Delphi

program History_variables;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

type
  THistoryVarType = record
    value: variant;
    timestamp: TDateTime;
    function ToString: string;
  end;

  THistoryVar = record
    Fvalue: variant;
    FHistory: TArray<THistoryVarType>;
  private
    procedure SetValue(const Value: Variant);
    function GetTimestamp: TDateTime;
  public
    property History: TArray<THistoryVarType> read FHistory;
    constructor Init(val: variant);
    function Dump: string;
    function Recall(steps: Integer): variant; overload;
    function Recall(timestamp: TDateTime): variant; overload;
    property Timestamp: TDateTime read GetTimestamp;
    property Value: Variant read Fvalue write SetValue;
  end;

{ THistoryVar }

function THistoryVar.Dump: string;
begin
  Result := '';
  for var h in FHistory do
    Result := Result + h.ToString + #10;
end;

function THistoryVar.GetTimestamp: TDateTime;
begin
  if Length(FHistory) = 0 then
    exit(0);
  Result := FHistory[high(FHistory)].timestamp;
end;

constructor THistoryVar.Init(val: variant);
begin
  SetLength(Fhistory, 0);
  SetValue(val);
end;

function THistoryVar.Recall(timestamp: TDateTime): variant;
begin
  for var h in FHistory do
  begin
    if h.timestamp = timestamp then
      exit(h.value);
  end;
  result := Fvalue;
end;

function THistoryVar.Recall(steps: Integer): variant;
begin
  if (steps <= 1) or (steps >= Length(FHistory)) then
    exit(value);

  result := FHistory[Length(FHistory) - steps - 1].value;
end;

procedure THistoryVar.SetValue(const Value: Variant);
begin
  SetLength(FHistory, Length(FHistory) + 1);
  FHistory[High(FHistory)].Value := Value;
  FHistory[High(FHistory)].timestamp := now;
  Fvalue := Value;
end;

{ THistoryVarType }

function THistoryVarType.ToString: string;
var
  dt: string;
begin
  DateTimeToString(dt, 'mm/dd/yyyy hh:nn:ss.zzz', timestamp);
  Result := format('%s -  %s', [dt, Value]);
end;

begin
  var v := THistoryVar.Init(0);
  v.Value := True;

  Sleep(200);
  if v.Value then
    v.Value := 'OK';

  Sleep(100);
  if v.Value = 'OK' then
    v.Value := PI;

  writeln('History of variable values:'#10);
  Writeln(v.Dump);

  Writeln('Recall 2 steps');
  Writeln(v.Recall(2));

  var t := v.History[3].timestamp;
  Writeln(#10'Recall to timestamp ', datetimetostr(t));
  Writeln(v.Recall(t));

  readln;
end.
Output:
History of variable values:

02/28/2021 19:50:32.512 -  0
02/28/2021 19:50:32.512 -  True
02/28/2021 19:50:32.712 -  OK
02/28/2021 19:50:32.813 -  3,14159265358979

Recall 2 steps
True

Recall to timestamp 28/02/2021 19:50:32
3,14159265358979

EchoLisp

No native support. We implement an anonymous stack associated with the variable, and a few syntax rules to define the needed operations.

(define-syntax-rule (make-h-var name) (define name (stack (gensym))))
(define-syntax-rule (h-get name) (stack-top name))
(define-syntax-rule (h-set name value) (push name value))
(define-syntax-rule (h-undo name) 
	(begin
	(pop name)
	(when ( stack-empty? name) (error "no more values" 'name))
	(stack-top name)))
						
(define-syntax-rule (h-values name) (stack->list name))
;; usage
(make-h-var x) x

(h-set x 42)  42
(h-set x 666) 666
(h-set x 'elvis) elvis
(h-values x)  (42 666 elvis) ;; historized values

(h-get x)  elvis
(h-undo x) 666
(h-undo x)  42
(h-undo x)   error: no more values x

Elena

ELENA 6.x :

import extensions;
import system'collections;
import system'routines;
import extensions'routines;
 
class HistoryVariable
{
    Stack  previous := new Stack();
    object value;
 
    Value
    {
        get() = value;
 
        set(value)
        {
            if ((this value) != nil)
            {
                previous.push(this value)
            };
 
            this value := value
        }
    }
 
    undo()
    {
        ifnot (previous.isEmpty())
        {
            value := previous.pop()
        }
        else
        {
            value := nil
        }
    }
 
    enumerator() => previous;
 
    string toPrintable() => this value;
}
 
public program()
{
    var o := new HistoryVariable();
    o.Value := 5;
    o.Value := "foo";
    o.Value := o.Value + "bar";
 
    console.printLine(o);
 
    o.forEach(printingLn);
 
    o.undo().undo().undo();
 
    console.printLine(o.Value ?? "nil")
}
Output:
foobar
foo
5
nil

Erlang

If we consider the usage of history variables, like not losing the old value by mistake or having a way to get an old value, then Erlang can really help. Being single assignment Erlang will not allow you to lose an old value, and it is certain that the previous values are always there. The downside is that you must handle this manually.

Output:
1> V1 = "123".
"123"
2> V1 = V1 ++ "qwe".
** exception error: no match of right hand side value "123qwe"
3> V2 = V1 ++ "qwe".
"123qwe"
4> V3 = V2 ++ "ASD".
"123qweASD"
5> V1. 
"123"
6> V2.
"123qwe"
7> V3.
"123qweASD"

Factor

USING: accessors combinators formatting kernel models.history ;

1 <history> {
    [ add-history ]
    [ value>> "Initial value: %u\n" printf ]
    [ 2 >>value add-history ]
    [ 3 swap value<< ]
    [ value>> "Current value: %u\n" printf ]
    [ go-back ]
    [ go-back ]
    [ value>> "Restored value: %u\n" printf ]
} cleave
Output:
Initial value: 1
Current value: 3
Restored value: 1

Forth

Forth does not have history variables, but it is trivial to define them. This one uses a linked list. The history variable is initialized to zero to avoid expensive sanity checks in H@. H-- undoes the assignment of a value and effectively returns a history variable to its former state.

: history create here cell+ , 0 , -1 , ;
: h@ @ @ ;
: h! swap here >r , dup @ , r> swap ! ;
: .history @ begin dup cell+ @ -1 <> while dup ? cell+ @ repeat drop ;
: h-- dup @ cell+ @ dup -1 = if abort" End of history" then swap ! ;

A sample session:

history z  ok
23 z h!  ok
z h@ . 23  ok
34 z h!  ok
z h@ . 34  ok
45 z h!  ok
z h@ . 45  ok
z .history 45 34 23  ok
z dup h-- h@ . 34  ok
z dup h-- h@ . 23  ok
z dup h-- h@ . 0  ok
z dup h-- h@ .
:86: End of history

Go

We're all in this for the extra points. Mallon and Takota seem happy with sequences, but time and timestamps were mentioned on LtU. Beyond a separate sequence for each history variable, timestamps enable multiple variables to be seen in a common temporal sequence. In Go, with it's attention to concurrency, this might be done with flexibility for proper handling of shared variables, and efficient handling of variables limited to a single thread.

package main

import (
    "fmt"
    "sort"
    "sync"
    "time"
)

// data type for history variable (its an int)
type history struct {
    timestamp tsFunc
    hs        []hset
}

// data type for timestamp generator
type tsFunc func() time.Time

// data type for a "set" event
type hset struct {
    int           // new value
    t   time.Time // timestamp
}

// newHistory creates a history variable
func newHistory(ts tsFunc) history {
    return history{ts, []hset{{t: ts()}}}
}   
    
// int returns the current value
func (h history) int() int {
    return h.hs[len(h.hs)-1].int
}
    
// set does what you expect and returns the timestamp recorded for the event
func (h *history) set(x int) time.Time {
    t := h.timestamp()
    h.hs = append(h.hs, hset{x, t})
    return t
}

// dump displays a complete history
func (h history) dump() {
    for _, hs := range h.hs {
        fmt.Println(hs.t.Format(time.StampNano), hs.int)
    }
}   
    
// recall recalls the value stored in the history variable at time t.
// if the variable had not been created yet, ok is false.
func (h history) recall(t time.Time) (int, /*ok*/ bool) {
    i := sort.Search(len(h.hs), func(i int) bool {
        return h.hs[i].t.After(t)
    })
    if i > 0 {
        return h.hs[i-1].int, true
    }
    return 0, false
}

// newTimestamper returns a function that generates unique timestamps.
// Use a single timestamper for multiple history variables to preserve
// an unambiguous sequence of assignments across the multiple history
// variables within a single goroutine.
func newTimestamper() tsFunc {
    var last time.Time
    return func() time.Time {
        if t := time.Now(); t.After(last) {
            last = t
        } else {
            last.Add(1)
        }
        return last
    }
}

// newProtectedTimestamper generates unique timestamps for concurrent
// goroutines.
func newProtectedTimestamper() tsFunc {
    var last time.Time
    var m sync.Mutex
    return func() (t time.Time) {
        t = time.Now()
        m.Lock() // m protects last
        if t.After(last) {
            last = t
        } else {
            last.Add(1)
            t = last
        }
        m.Unlock()
        return
    }
}

func main() {
    // enable history variable support appropriate for single goroutine.
    ts := newTimestamper()
    // define a history variable
    h := newHistory(ts)
    // assign three values.  (timestamps kept for future reference.)
    ref := []time.Time{h.set(3), h.set(1), h.set(4)}
    // non-destructively display history
    fmt.Println("History of variable h:")
    h.dump() 
    // recall the three values.  (this is non-destructive as well, but
    // different than the dump in that values are recalled by time.)
    fmt.Println("Recalling values:")
    for _, t := range ref {
        rv, _ := h.recall(t)
        fmt.Println(rv)
    }
}
Output:
History of variable h:
Dec  3 18:51:17.292260000 0
Dec  3 18:51:17.292262000 3
Dec  3 18:51:17.292264000 1
Dec  3 18:51:17.292270000 4
Recalling values:
3
1
4

Haskell

There are no native Haskell history variables, but they are simple to implement.

import Data.IORef

newtype HVar a = HVar (IORef [a])

newHVar :: a -> IO (HVar a)
newHVar value = fmap HVar (newIORef [value])

readHVar :: HVar a -> IO a
readHVar (HVar ref) = fmap head (readIORef ref)

writeHVar :: a -> HVar a -> IO ()
writeHVar value (HVar ref) = modifyIORef ref (value:)

undoHVar :: HVar a -> IO ()
undoHVar (HVar ref) = do
    (_ : history) <- readIORef ref
    writeIORef ref history

getHistory :: HVar a -> IO [a]
getHistory (HVar ref) = readIORef ref

-- Testing
main :: IO ()
main = do
    var <- newHVar 0
    writeHVar 1 var
    writeHVar 2 var
    writeHVar 3 var
    getHistory var >>= print
    undoHVar var
    undoHVar var
    undoHVar var

J

J does not natively support "history variables", but the functionality is easy to add:

varref_hist_=:'VAR','_hist_',~]
set_hist_=:4 :0
  V=.varref x
  if.0>nc<V do.(<V)=:''end.
  (<V)=.V~,<y
  y
)
getall_hist_=:3 :0
  (varref y)~
)
length_hist_=: #@getall
get_hist_=: _1 {:: getall

Example use:

   'x' set_hist_ 9
9
   'x' set_hist_ 10
10
   'x' set_hist_ 11
11
   get_hist_ 'x'
11
   length_hist_ 'x'
3
   getall_hist_ 'x'
┌─┬──┬──┐
91011
└─┴──┴──┘

Note that each value is contained in a box, so different values do not need to be type compatible with each other. If this is considered a defect then assertions could be added to enforce type compatibility across assignments.

Note that only nouns are supported here: If you want to store verbs using this mechanism you will need to use their gerunds.

Finally, note that the distinction between relevant history and irrelevant history depend on the application, and perhaps on the user. Also, necessity suggests that a lot of the history detail will be irrelevant for many purposes.

Java

Java does not support history variables, but they are easy to implement using the lists that come with Java's Collections framework.

Java Integer with History

This implementation does not allow the History Variable to be "empty". It can be assigned one or multiple "nulls", but it can never have an undefined value (such as being created and not initialized).

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * A class for an "Integer with a history".
 * <p>
 * Note that it is not possible to create an empty Variable (so there is no "null") with this type. This is a design
 * choice, because if "empty" variables were allowed, reading of empty variables must return a value. Null is a
 * bad idea, and Java 8's Optional<T> (which is somewhat like the the official fix for the null-bad-idea) would
 * make things more complicated than an example should be.
 */
public class IntegerWithHistory {

    /**
     * The "storage Backend" is a list of all values that have been ever assigned to this variable. The List is
     * populated front to back, so a new value is inserted at the start (position 0), and older values move toward the end.
     */
    private final List<Integer> history;

    /**
     * Creates this variable and assigns the initial value
     *
     * @param value initial value
     */
    public IntegerWithHistory(Integer value) {
        history = new LinkedList<>();
        history.add(value);
    }

    /**
     * Sets a new value, pushing the older ones back in the history
     *
     * @param value the new value to be assigned
     */
    public void set(Integer value) {
        //History is populated from the front to the back, so the freshest value is stored a position 0
        history.add(0, value);
    }

    /**
     * Gets the current value. Since history is populuated front to back, the current value is the first element
     * of the history.
     *
     * @return the current value
     */
    public Integer get() {
        return history.get(0);
    }

    /**
     * Gets the entire history all values that have been assigned to this variable.
     *
     * @return a List of all values, including the current one, ordered new to old
     */
    public List<Integer> getHistory() {
        return Collections.unmodifiableList(this.history);
    }

    /**
     * Rolls back the history one step, so the current value is removed from the history and replaced by it's predecessor.
     * This is a destructive operation! It is not possible to rollback() beyond the initial value!
     *
     * @return the value that had been the current value until history was rolled back.
     */
    public Integer rollback() {
        if (history.size() > 1) {
            return history.remove(0);
        } else {
            return history.get(0);
        }
    }
}

Test Program:

public class TestIntegerWithHistory {

    public static void main(String[] args) {

        //creating and setting three different values
        IntegerWithHistory i = new IntegerWithHistory(3);
        i.set(42);
        i.set(7);

        //looking at current value and history
        System.out.println("The current value of i is :" + i.get());
        System.out.println("The history of i is :" + i.getHistory());

        //demonstrating rollback
        System.out.println("Rolling back:");
        System.out.println("returns what was the current value: " + i.rollback());
        System.out.println("after rollback: " + i.get());
        System.out.println("returns what was the current value: " + i.rollback());
        System.out.println("after rollback: " + i.get());
        System.out.println("Rolling back only works to the original value: " + i.rollback());
        System.out.println("Rolling back only works to the original value: " + i.rollback());
        System.out.println("So there is no way to 'null' the variable: " + i.get());

    }
}
Output:
The current value of i is :7
The history of i is :[7, 42, 3]
Rolling back:
returns what was the current value: 7
after rollback: 42
returns what was the current value: 42
after rollback: 3
Rolling back only works to the original value: 3
Rolling back only works to the original value: 3
So there is no way to 'null' the variable: 3

Java History for "any class" using Generics

This implementation does not allow the History Variable to be "empty". It can be assigned one or multiple "nulls", but it can never have an undefined value (such as being created and not initialized). Test Program using a "String with History":

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * A Generic class for an "Anything with a history".
 * <p>
 * Note that it is not possible to create an empty Variable (so there is no "null") with this type. This is a design
 * choice, because if "empty" variables were allowed, reading of empty variables must return a value. Null is a
 * bad idea, and Java 8's Optional<T> (which is somewhat like the the official fix for the null-bad-idea) would
 * make things more complicated than an example should be.
 * <p>
 * Also note that this "really works" only with constant Ts. If somebody keeps a reference to an assigned value,
 * and is able to modify the state of this value through the reference , this will not be reflected in the history!
 */
public class WithHistory<T> {

    /**
     * The "storage Backend" is a list of all values that have been ever assigned to this variable. The List is
     * populated front to back, so a new value is inserted at the start (position 0), and older values move toward the end.
     */
    private final List<T> history;

    /**
     * Creates this variable and assigns the initial value
     *
     * @param value initial value
     */
    public WithHistory(T value) {
        history = new LinkedList<>();
        history.add(value);
    }

    /**
     * Sets a new value, pushing the older ones back in the history
     *
     * @param value the new value to be assigned
     */
    public void set(T value) {
        //History is populated from the front to the back, so the freshest value is stored a position 0
        history.add(0, value);
    }

    /**
     * Gets the current value. Since history is populuated front to back, the current value is the first element
     * of the history.
     *
     * @return the current value
     */
    public T get() {
        return history.get(0);
    }

    /**
     * Gets the entire history all values that have been assigned to this variable.
     *
     * @return a List of all values, including the current one, ordered new to old
     */
    public List<T> getHistory() {
        return Collections.unmodifiableList(this.history);
    }

    /**
     * Rolls back the history one step, so the current value is removed from the history and replaced by it's predecessor.
     * This is a destructive operation! It is not possible to rollback() beyond the initial value!
     *
     * @return the value that had been the cueent value until history was rolled back.
     */
    public T rollback() {
        if (history.size() > 1) {
            return history.remove(0);
        } else {
            return history.get(0);
        }
    }
}
Output:
The current value is :And now to something completely different.
The history is:[And now to something completely different., See you later History!, Hello History!]
Rolling back:
returns what was the current value: And now to something completely different.
after rollback: See you later History!
returns what was the current value: See you later History!
after rollback: Hello History!
Rolling back only works to the original value: Hello History!
Rolling back only works to the original value: Hello History!
So there is no way to 'null' the variable: Hello History!

Julia

Julia currently does not support overloading the assignment "=" operator.

mutable struct Historied
    num::Number
    history::Vector{Number}
    Historied(n) = new(n, Vector{Number}())
end

assign(y::Historied, z) = (push!(y.history, y.num); y.num = z; y)

x = Historied(1)

assign(x, 3)
assign(x, 5)
assign(x, 4)

println("Past history of variable x: $(x.history). Current value is $(x.num)")
Output:
Past history of variable x: Number[1, 3, 5]. Current value is 4

Kotlin

// version 1.1.4

class HistoryVariable<T>(initialValue: T) {
    private val history = mutableListOf<T>()

    var currentValue: T
        get() = history[history.size - 1]
        set(value) {
           history.add(value)
        }

    init {
        currentValue = initialValue
    }

    fun showHistory() {
        println("The variable's history, oldest values first, is:")
        for (item in history) println(item)
    }
}

fun main(args: Array<String>) {
    val v = HistoryVariable(1)
    v.currentValue = 2
    v.currentValue = 3
    v.showHistory()
    println("\nCurrentvalue is ${v.currentValue}")
}
Output:
The variable's history, oldest values first, is:
1
2
3

Currentvalue is 3

Lua

Lua does not natively support history variables. However, as with other languages here, something roughly equivalent could be implemented with a "stack wrapper". The only complicated issue might be how to treat nil's (null values). The implementation below allows initial nil's, and allows undo()'s back to nil, but does not consider nil as part of the "history".

Via metatable

-- History variables in Lua 6/12/2020 db
local HistoryVariable = {
  new = function(self)
    return setmetatable({history={}},self)
  end,
  get = function(self)
    return self.history[#self.history]
  end,
  set = function(self, value)
    self.history[#self.history+1] = value
  end,
  undo = function(self)
    self.history[#self.history] = nil
  end,
}
HistoryVariable.__index = HistoryVariable

local hv = HistoryVariable:new()
print("defined:", hv)
print("value is:", hv:get())
--
hv:set(1); print("set() to:", hv:get())
hv:set(2); print("set() to:", hv:get())
hv:set(3); print("set() to:", hv:get())
--
print("history:", table.concat(hv.history,","))
--
hv:undo(); print("undo() to:", hv:get())
hv:undo(); print("undo() to:", hv:get())
hv:undo(); print("undo() to:", hv:get())
Output:
defined:        table: 0000000000939240
value is:       nil
set() to:       1
set() to:       2
set() to:       3
history:        1,2,3
undo() to:      2
undo() to:      1
undo() to:      nil

Via closure

If a desire is to keep history private and immutable, then..

-- History variables in Lua 6/12/2020 db
local function HistoryVariable()
  local history = {}
  return {
    get = function()
      return history[#history]
    end,
    set = function(value)
      history[#history+1] = value
    end,
    undo = function()
      history[#history] = nil
    end,
    getHistory = function()
      local clone = {}
      for k,v in pairs(history) do clone[k]=v end
      return clone
    end
  }
end

local hv = HistoryVariable()
print("defined:", hv)
print("value is:", hv.get())
--
hv.set(1); print("set() to:", hv.get())
hv.set(2); print("set() to:", hv.get())
hv.set(3); print("set() to:", hv.get())
--
print("history:", table.concat(hv.getHistory(),","))
--
hv.undo(); print("undo() to:", hv.get())
hv.undo(); print("undo() to:", hv.get())
hv.undo(); print("undo() to:", hv.get())
Output:
defined:        table: 0000000000a59500
value is:       nil
set() to:       1
set() to:       2
set() to:       3
history:        1,2,3
undo() to:      2
undo() to:      1
undo() to:      nil

M2000 Interpreter

We can make objects type of Group to act as History Variables. Each group has a pointer to a stack object (a linked list). First we see how we work with Stack (each module/function see a "current stack", we can make pointers to new stacks, but we can't get pointer of current stack). There are some statement no demonstrate here, such as Shift and ShiftBack (move top to a place, and move back to top), and Over (make new items by copying items).

Flush ' empty curtrent stack
\\ a is a pointer to a new stack object
a=stack:=1,2@,3%
Print Len(A)=3
For i=1 to Len(a) {
      Print StackType$(a, i)="Number"
}
b=stack
Print len(b)=0
Push 1, 2 \\ to current stack
Stack b {
      \\ make b the current stack
      Data 1, 2, 3
}  ' Data add to bottom
\\ now current stack get the old object
Stack b {Push 1, 2, 3 } ' Push add to top, so 3 is at top
Stack b {
      While not empty {
            Read k  ' Read used to pop value to a variable
            \\ number pop value in an expression
            Print  k, number,  ' 3 2 1 1 2 3
      }
      Print
}
z=[]  ' [] pop all values from current stack to a new stack, and return a pointer
Print z  ' 2 1
z=Stack(a, z,a, z)  ' merge stack objects, to a new one, preserve a and z
Print Len(z)
\\ empty a using a new object
a=stack
b=stack:=1,2,3
\\ z has two stack objects
z=stack:= a, b
Stack b { data 1000}
b=stack ' b point to a new stack
\\ we get pointer back
b=stackitem(z, 2)
Print stackitem(b, 4)=1000

So now lets see the code:

Module CheckHistoryVariables {
      Class History {
      Private:
            myvalue=stack
      Public:
            Group Count {
                  Value {
                        link parent myvalue to m 
                        =Len(m)
                  }
            }
            Function CopyMe {
                  m=This
                  .myvalue<=stack(.myvalue)
                  =Group(m)
            }
            Group CopyValues {
                  Value {
                        link parent myvalue to m
                        =Stack(m)
                  }
            }
            Function Values (x as long) {
                  if x>=0 and x<=len(.myvalue) then  =StackItem(.myvalue, x)
                  Else Error "Fault index"
            }
            Module Back {
                  if len(.myvalue)<2 then exit
                 Stack .myvalue {Drop}
            }
            Operator "++" {
                  Stack .myvalue {
                        Push stackitem()+1
                  }
            }
            Operator "--" {
                  Stack .myvalue {
                        Push stackitem()-1
                  }
            }
            Operator "+="  (x) {
                  Stack .myvalue {
                        Push stackitem()+x
                  }       }
            Operator "-=" (x) {
                  Stack .myvalue {
                        Push stackitem()-x
                  }       
            }
            Operator "/=" (x){
                  if x==0 then error "division by zero"
                  Stack .myvalue {
                        Push stackitem()/x
                  } 
            }
            Operator "*=" (x){
                  Stack .myvalue {
                        Push stackitem()*x
                  }             
            }
            Value {
                  =StackItem(.myvalue)
            }
            Set {
                   Read x : Stack .myvalue { Push x}
            }
      Class:
            Module History {
                  If Match("N") then Read x : Stack .myvalue { Push x}
            }
      }
      
      N=History()
      N=1
      N=2
      N=3
      Print N, N.Values(2), N.Values(3), N.Count
      \\ Get a copy of history
      m=N.CopyValues
      Print len(m)=3
      \\ just show all
      Print m  ' 3 2 1
      \\ or iterate from last to first
      k=each(m, -1, 1)
      While k {
            Print Stackitem(k)  \\  1 NL 2 NL 3  (NL = new line)
      }
      N1=N.CopyMe()
      N=5
      N1=4
      N=6
      Print N
      Print N1.Count=4, N.Count=5
      Print N1, N
      Print N.CopyValues ' 6 5 3 2 1
      Print N1.CopyValues ' 4 3 2 1
      Print N1<N
      N=N+1
      Print N.Count=6
      Print N.CopyValues ' 6 5 3 2 1
      Print "Go Back"
      While N.Count>1 {
            N.Back
            Print N
      }
      N+=10
      N*=2
      Print N.CopyValues  ' 22 11 1
}
CheckHistoryVariables

\\ for strings
Module CheckStringHistoryVariables {
      Class History$ {
      Private:
            myvalue=stack
      Public:
            Group Count {
                  Value {
                        link parent myvalue to m 
                        =Len(m)
                  }
            }
            Function CopyMe {
                  m=This
                  .myvalue<=stack(.myvalue)
                  =Group(m)
            }
            Group CopyValues {
                  Value {
                        link parent myvalue to m
                        =Stack(m)
                  }
            }
            Function Values$ (x as long) {
                  if x>=0 and x<=len(.myvalue) then  =StackItem$(.myvalue, x)
                  Else Error "Fault index"
            }
            Module Back {
                  if len(.myvalue)<2 then exit
                 Stack .myvalue {Drop}
            }
            Operator "+="  (x$) {
                  Stack .myvalue {
                        Push stackitem$()+x$
                  }       }
            Value {
                  =StackItem$(.myvalue)
            }
            Set {
                   Read x$ : Stack .myvalue { Push x$}
            }
      Class:
            Module History {
                  If Match("S") then Read x$ : Stack .myvalue { Push x$}
            }
      }
      N$=History$("First")
      N$="Second"
      N$="Third"
      Print N.Count=3
      M=N.CopyValues
      K=Each(M, -1, 1)
      While K {
            Print StackItem$(K)
      }
      N$+=" and this"
      Print N.Count=4
      Print N.CopyValues
      N.Back
      Print N.Count=3
      Print N.CopyValues
      Print N.Values$(2)="Second"
      Input "New value:", N$
      Print N$
      Print N.Count=4
      Print N.CopyValues
}
CheckStringHistoryVariables

Nim

Nim doesn’t provide history variables, but it is easy to implement them. As Nim is statically typed, we define history variable type in a generic way.

type HistoryVar[T] = object
  hist: seq[T]

func initHistoryVar[T](value: T = T.default): HistoryVar[T] =
  ## Initialize a history variable with given value.
  result.hist.add value

func set(h: var HistoryVar; value: h.T) =
  ## Set the history variable to given value.
  h.hist.add value

func get(h: HistoryVar): h.T =
  ## Return the current value of history variable.
  h.hist[^1]

proc showHistory(h: HistoryVar) =
  ## Show the history starting from oldest values.
  for i, value in h.hist:
    echo i, ": ", value

func pop(h: var HistoryVar): h.T =
  ## Pop the current value and return it.
  if h.hist.len > 1: h.hist.pop() else: h.hist[0]


when isMainModule:

  var h = initHistoryVar[int]()   # Initialized to 0.

  echo "Assigning three values: 1, 2, 3"
  h.set(1)      # 0, 1
  h.set(2)      # 0, 1, 2
  h.set(3)      # 0, 1, 2, 3

  echo "History (oldest values first):"
  h.showHistory()

  echo "Current value is ", h.get()

  echo "Recall the three values:"
  echo h.pop()  # -> 3, last value removed.
  echo h.pop()  # -> 2, last value removed.
  echo h.pop()  # -> 1, last value removed.

  echo "History (note that initial value can never be removed):"
  h.showHistory()
Output:
Assigning three values: 1, 2, 3
History (oldest values first):
0: 0
1: 1
2: 2
3: 3
Current value is 3
Recall the three values:
3
2
1
History (note that initial value can never be removed):
0: 0

Oberon-2

MODULE HVar;
IMPORT Out, Conv;
TYPE
	(* Generic Object *)
	Object* = POINTER TO ObjectDesc;
	ObjectDesc = RECORD
		Show: PROCEDURE(o:Object);
		AsString: PROCEDURE(o: Object; VAR str: ARRAY OF CHAR);
	END;
	
	(* Integers *)
	Integer = POINTER TO IntegerDesc;
	IntegerDesc = RECORD (ObjectDesc)
		val: INTEGER;
	END;
	
	(* Chars *)
	Char = POINTER TO CharDesc;
	CharDesc = RECORD (ObjectDesc)
		val: CHAR;
	END;
	
	Node = POINTER TO NodeDesc;
	NodeDesc = RECORD
		val: Object;
		next: Node;
	END;
	
	(* History Variable *)
	HVar* = POINTER TO HVarDesc;
	HVarDesc = RECORD
		first, last: Node;
		size-: INTEGER;
	END;
	
	PROCEDURE CharAsString(o:Object; VAR dst: ARRAY OF CHAR);
	BEGIN
		IF LEN(dst) >= 2 THEN
			dst[1] := 0X;
		END;
		dst[0] := o(Char)^.val
	END CharAsString;
	
	PROCEDURE IntAsString(o:Object; VAR dst: ARRAY OF CHAR);
	BEGIN
		Conv.ConvInt(o(Integer)^.val,dst);
	END IntAsString;
	
	PROCEDURE ShowInt(o:Object);
	BEGIN
		Out.Int(o(Integer)^.val,10);
	END ShowInt;
	
	PROCEDURE ShowChar(o:Object);
	BEGIN
		Out.Char(o(Char)^.val);
	END ShowChar;
	
	PROCEDURE BoxChar(val: CHAR): Char;
	VAR
		c: Char;
	BEGIN
		NEW(c);
		c^.val := val;
		c^.Show := ShowChar;
		c^.AsString := CharAsString;
		RETURN c;
	END BoxChar;
	
	PROCEDURE BoxInt(val:INTEGER): Integer;
	VAR
		i: Integer;
	BEGIN
		NEW(i); 
		i^.val := val;
		i^.Show := ShowInt;
		i^.AsString := IntAsString;
		RETURN i;
	END BoxInt;
	
	PROCEDURE InitNode(): Node;
	VAR
		l: Node;
	BEGIN
		NEW(l);
		l.val := NIL;
		l.next := NIL;
		RETURN l;
	END InitNode;
	
	PROCEDURE InitHVar(): HVar;
	VAR
		hv: HVar;
	BEGIN
		NEW(hv);
		hv.first := NIL;
		hv.last := NIL;
		hv.size := 0;
		RETURN hv;
	END InitHVar;
	
	PROCEDURE (v: HVar) Value(): Object;
	BEGIN
		RETURN v^.first^.val;
	END Value;
	
	PROCEDURE (v: HVar) Set(o: Object);
	VAR
		l: Node;
	BEGIN
		l := InitNode();
		l^.val := o;
		IF (v^.first = v^.last) & (v^.first = NIL) THEN
			v^.first := l;
			v^.last := l;
			INC(v^.size);
		ELSIF (v^.first = v^.last) & (v^.first # NIL) THEN
			v^.first^.next := l;
			v^.last := v^.first.next;
			INC(v^.size);
		ELSIF (v^.first # v^.last) THEN
			v^.last^.next := l;
			v^.last := l;
			INC(v^.size);
		END
	END Set;
	
	PROCEDURE (v: HVar) Undo(): Object;
	VAR 
		o: Object;
	BEGIN
		IF (v^.first = v^.last) & (v^.first = NIL) THEN
			o := NIL;
		ELSIF (v^.first = v^.last) & (v^.first # NIL) THEN
			o := v^.first^.val;
			v^.first := NIL;
			v^.last := NIL;
			DEC(v^.size);
		ELSE
			o := v^.first^.val;
			v^.first := v^.first^.next;
			DEC(v^.size);
		END;
		RETURN o;
	END Undo;
	
	PROCEDURE (v: HVar) Print();
	VAR
		iter : Node;
	BEGIN
		iter := v.first;
		WHILE(iter # NIL) DO
			iter^.val^.Show(iter^.val);
			iter := iter^.next;
		END;
		Out.Ln;
	END Print;
	
	PROCEDURE ShowVal(val: Object);
	VAR
		s: ARRAY 128 OF CHAR;
	BEGIN
		val^.AsString(val,s);
		Out.String("> ");Out.String(s);Out.Ln;
	END ShowVal;
VAR
	history: HVar;
	
BEGIN
	history := InitHVar();
	history.Set(BoxChar(64X));
	history.Set(BoxInt(10));
	history.Set(BoxInt(15));
	history.Set(BoxInt(20));
	history.Print();
	ShowVal(history.Undo());
	ShowVal(history.Undo());
	ShowVal(history.Undo());
END HVar.

OCaml

The easiest solution is to use the Stack module coming with OCaml's standard library:

open Stack
(* The following line is only for convenience when typing code *)
module H = Stack

let show_entry e =
    Printf.printf "History entry: %5d\n" e

let () =
  let  hs = H.create() in
  H.push 111 hs ;
  H.push 4 hs ;
  H.push 42 hs ;
  H.iter show_entry hs;
  hs |> H.pop |> Printf.printf "%d\n";
  hs |> H.pop |> Printf.printf "%d\n";
  hs |> H.pop |> Printf.printf "%d\n"
Output:
History entry:    42
History entry:     4
History entry:   111
42
4
111 

OxygenBasic

Simple history class for fixed length types that do not contain volatile pointer members.

'============
class History
'============

indexbase 0

string buf
sys    ii,ld,pb

method constructor(sys n=1000, l=sizeof sys) {buf=nuls n*l : pb=strptr buf : ld=l : ii=0}
method destructor () {clear}
'
method setup(sys n=1000, l=sizeof sys) {buf=nuls n*l : pb=strptr buf : ld=l : ii=0}
method clear()                {buf="" : pb=0 : ld=0 : ii=0}
method max  (sys i)           {if i>ii{ii=i}}
method count() as sys         {return ii}
method size () as sys         {return ld}
'
method get  (any*p,i)         {copy @p, pb+i*ld,ld }           'out
method add  (any*p)           {copy pb+ii*ld,@p,ld : ii++}     'in
method put  (any*p,sys i)     {copy pb+i*ld,@p,ld : max i}     'in
'
end class

'====
'TEST
'====

'this works for fixed length types

'it will not work for types containing
'volatile pointers. eg: string members

type vector double x,y,z

vector v

new History hv(1000,sizeof v) 'give number of records and variable size

sys i
for i=0 to 9
  v<=i,i*10,i*100 'assign new values to vector
  hv.add v      'add to history
next

string tab=chr(9) : cr=chr(13)+chr(10)
string pr="Data History of v" cr cr
pr+="n" tab "x" tab "y" tab "z" cr
vector sv
'
for i=hv.count()-1 to 0 step -1
  hv.get sv,i
  pr+=i tab sv.x tab sv.y tab sv.z cr
next

print pr 'result '9,90,900 : 8,80,800 ... 

del hv

PARI/GP

default(histsize, 1000) \\ or some other positive number to suit
1+7
sin(Pi)
2^100
\a1 \\ display history item #1, etc.
% \\ alternate syntax
%1 \\ alternate syntax
\a2
\a3
[%1, %2, %3] \\ or any other command using these values

Peloton

Turn history on <@ DEFHST>__on</@> 
Notify Protium we are interested in the variable mv 
<@ DEFHST>mv</@> 
Assign a value: <@ LETVARLIT>mv|first value</@><@ SAYVAR>mv</@> 
Reassign the value: <@ LETVARLIT>mv|second value</@><@ SAYVAR>mv</@> 
Reassign the value: <@ LETVARLIT>mv|third value</@><@ SAYVAR>mv</@> 
Dump history <@ SAYDMPHSTVAR>mv</@> 
Current value: <@ SAYVAR>mv</@>
Undo once: <@ ACTUNDVAR>mv</@><@ SAYVAR>mv</@> 
Undo twice: <@ ACTUNDVAR>mv</@><@ SAYVAR>mv</@> 
Turn history off <@ DEFHST>__off</@>

Same code, Simplified Chinese dialect

Turn history on <# 定义变量史>__on</#> 
Notify Protium we are interested in the variable mv 
<# 定义变量史>mv</#> 
Assign a value: <# 指定变量字串>mv|first value</#><# 显示变量>mv</#> 
Reassign the value: <# 指定变量字串>mv|second value</#><# 显示变量>mv</#> 
Reassign the value: <# 指定变量字串>mv|third value</#><# 显示变量>mv</#> 
Dump history <# 显示全内容变量史变量>mv</#> 
Current value: <# 显示变量>mv</#>
Undo once: <# 运行撤消变量>mv</#><# 显示变量>mv</#> 
Undo twice: <# 运行撤消变量>mv</#><# 显示变量>mv</#> 
Turn history off <# 定义变量史>__off</#>
Output:
Turn history on  
Notify Protium we are interested in the variable mv 
 
Assign a value: first value 
Reassign the value: second value 
Reassign the value: third value 
Dump history third value^second value^first value^ 
Current value: third value
Undo once: second value 
Undo twice: first value 
Turn history off  

Perl

Implemented via tie (and what's the usefulness of this?)

package History;

sub TIESCALAR {
	my $cls = shift;
	my $cur_val = shift;
	return bless [];
}

sub FETCH {
	return shift->[-1]
}

sub STORE {
	my ($var, $val) = @_;
	push @$var, $val;
	return $val;
}

sub get(\$) { @{tied ${+shift}} }
sub on(\$) { tie ${+shift}, __PACKAGE__ } 
sub off(\$) { untie ${+shift} }
sub undo(\$) { pop @{tied ${+shift}} }

package main;

my $x = 0;
History::on($x);

for ("a" .. "d") { $x = $_ }

print "History: @{[History::get($x)]}\n";

for (1 .. 3) {
	print "undo $_, ";
	History::undo($x);
	print "current value: $x\n";
}

History::off($x);
print "\$x is: $x\n";
Output:
History: a b c d
undo 1, current value: c
undo 2, current value: b
undo 3, current value: a
$x is: a

Phix

No native support, but trivial to implement.
If you only need the history for a single variable, you can just do this, though it does not work under pwa/p2js:

without js -- (desktop/Phix only)
sequence history = {}
 
type hvt(object o)
    history = append(history,o)
    return true
end type
 
hvt test = 1
test = 2
test = 3
?{"current",test}
?{"history",history}
Output:
{"current",3}
{"history",{1,2,3}}

Multiple history variables would require that routines must be invoked to create, update, and inspect them, and would be pwa/p2js compatible.
Writing this as a separate reusable component (but omitting destroy/freelist handling for simplicity):

-- history.e
sequence histories = {}

global function new_history_id(object v)
    histories = append(histories,{v})
    return length(histories)
end function

global procedure set_hv(integer hv, object v)
    histories[hv] = append(histories[hv],v)
end procedure

global function get_hv(integer hv)
    return histories[hv][$]
end function

global function get_hv_full_history(integer hv)
    return histories[hv]
end function

And use it like this

include history.e

constant test2 = new_history_id(1)
set_hv(test2, 2)
set_hv(test2, 3)
?{"current",get_hv(test2)}
?{"history",get_hv_full_history(test2)}

Same output. Of course test2 does not have to be a constant, but it may help.

PicoLisp

(de setH ("Var" Val)
   (when (val "Var")
      (with "Var"
         (=: history (cons @ (: history))) ) )
   (set "Var" Val) )

(de restoreH ("Var")
   (set "Var" (pop (prop "Var" 'history))) )

Test:

: (setH 'A "Hello world")
-> "Hello world"

: (setH 'A '(a b c d))
-> (a b c d)

: (setH 'A 123)
-> 123

: A
-> 123

: (get 'A 'history)
-> ((a b c d) "Hello world")

: (restoreH 'A)
-> (a b c d)

: (restoreH 'A)
-> "Hello world"

: A
-> "Hello world"

: (restoreH 'A)
-> NIL

PL/I

declare t float controlled;

do i = 1 to 5; /* a loop to read in and save five values. */
allocate t; get (t);
end;

do while (allocation(t) > 0); /* a loop to retrieve the values. */
put (t); free t;
end;

PureBasic

; integer history variable

Structure historyint
    List value.i()
EndStructure

Procedure SetInt (*var.historyint, val.i)
    AddElement(*var\value())
    
    If (ListSize(*var\value()) = 1)
        *var\value() = 0
        AddElement(*var\value())

    EndIf
    
    *var\value() = val  
EndProcedure

Procedure ShowHistory (*var.historyint)
    ForEach *var\value()
        Debug *var\value()
    Next
EndProcedure

Procedure UndoInt (*var.historyint)
    If (ListSize(*var\value()) = 1)
        ProcedureReturn
    EndIf
    
    DeleteElement(*var\value())  
EndProcedure

;----------------------------------------------

Define x.historyint

For i = 0 To 3
    setint(x, Random(50)+100 )
Next

Debug "x history:"
ShowHistory(x)

Debug ""

For i = 0 To 3
    UndoInt(x)
    Debug "undo, x = "+Str(x\value())
Next
Output:
x history:
0
131
109
143
108

undo, x = 143
undo, x = 109
undo, x = 131
undo, x = 0

Python

import sys

HIST = {}

def trace(frame, event, arg):
    for name,val in frame.f_locals.items():
        if name not in HIST:
            HIST[name] = []
        else:
            if HIST[name][-1] is val:
                continue
        HIST[name].append(val)
    return trace

def undo(name):
    HIST[name].pop(-1)
    return HIST[name][-1]

def main():
    a = 10
    a = 20

    for i in range(5):
        c = i

    print "c:", c, "-> undo x3 ->",
    c = undo('c')
    c = undo('c')
    c = undo('c')
    print c
    print 'HIST:', HIST

sys.settrace(trace)
main()
Output:
c: 4 -> undo x3 -> 1
HIST: {'a': [10, 20], 'i': [0, 1, 2, 3, 4], 'c': [0, 1], 'name': ['c']}


Quackery

Quackery does not have variables, it has ancillary stacks that can serve, amongst their uses, as variables and as history variables. Given an ancillary stack x, the following Quackery words are relevant.

  • x put moves an item from the data stack to the ancillary stack x.
  • x take moves an item from the ancillary stack x to the data stack.
  • x share copies the top of the ancillary stack x to the data stack.
  • x replace replaces the top item on the ancillary stack x with the item on top of the data stack.
  • x behead drop leaves a copy of the ancillary stack x on the data stack as a nest (dynamic array).


The requirements of this task demonstrated as a dialogue in the Quackery shell.

/O> [ stack ] is x
... 3 x put 
... 4 x put
... 5 x put
... x behead drop echo cr
... x take echo cr
... x take echo cr
... x take echo cr
... 
[ 3 4 5 ]
5
4
3


Racket

Racket does not come with history variables, but they can be provided as a library as follows:

#lang racket

(require rackunit)

(struct hvar (current history) #:mutable)

(define (make-hvar v) (hvar v empty))

(define (hvar-set! hv new)
  (match-define (hvar cur hist) hv)
  (set-hvar-history! hv (cons cur hist))
  (set-hvar-current! hv new))

(define (hvar-undo! hv)
  (match-define (hvar cur (cons old hist)) hv)
  (set-hvar-current! hv old)
  (set-hvar-history! hv hist))

;; unit tests
(define hv (make-hvar 0))
(hvar-set! hv 1)
(check-equal? (hvar-current hv) 1)
(hvar-set! hv 2)
(hvar-set! hv 3)
(check-equal? (hvar-history hv) '(2 1 0))
(hvar-undo! hv)
(hvar-undo! hv)
(hvar-undo! hv)
(check-equal? (hvar-current hv) 0)

Raku

(formerly Perl 6)

Works with: Rakudo version 2018.03
class HistoryVar {
    has @.history;
    has $!var handles <Str gist FETCH Numeric>;
    method STORE($val) is rw {
        push @.history, [now, $!var];
        $!var = $val;
    }
}

my \foo = HistoryVar.new;

foo = 1;
foo = 2;
foo += 3;
foo = 42;

.say for foo.history;
say "Current value: {foo}";
Output:
[Instant:1523396079.685629 (Any)]
[Instant:1523396079.686844 1]
[Instant:1523396079.687130 2]
[Instant:1523396079.687302 5]
Current value: 42

REXX

Version 1

The REXX language doesn't support histories, but can be coded with little trouble.

The history list part of the &nbsp' varSet   subroutine could be separated into its
own if you wanted to keep the subroutine's function pure.

/*REXX program demonstrates a method to track history of assignments to a REXX variable.*/
varSet!.=0                                       /*initialize the all of the VARSET!'s. */
call varSet 'fluid',min(0,-5/2,-1)     ;    say 'fluid=' fluid
call varSet 'fluid',3.14159            ;    say 'fluid=' fluid
call varSet 'fluid',' Santa  Claus'    ;    say 'fluid=' fluid
call varSet 'fluid',,999
say 'There were' result "assignments (sets) for the FLUID variable."
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
varSet: arg ?x;  parse arg ?z, ?v, ?L            /*obtain varName, value, optional─List.*/
if ?L=='' then do                                /*not la ist,  so set the  X  variable.*/
               ?_=varSet!.0.?x+1                 /*bump the history count  (# of SETs). */
               varSet!.0.?x=?_                   /*   ... and store it in the "database"*/
               varSet!.?_.?x=?v                  /*   ... and store the  SET  value.    */
               call value(?x),?v                 /*now,  set the real  X  variable.     */
               return ?v                         /*also, return the value for function. */
               end
say                                              /*show a blank line for readability.   */
            do ?j=1 to ?L while ?j<=varSet!.0.?x /*display the list of  "set"  history. */
            say 'history entry' ?j "for var" ?z":" varSet!.?J.?x
            end   /*?j*/
return ?j-1                                      /*return the number of assignments.    */

output

fluid= -2.5
fluid= 3.14159
fluid=  Santa  Claus

history entry 1 for var fluid: -2.5
history entry 2 for var fluid: 3.14159
history entry 3 for var fluid:  Santa  Claus
There were 3 assignments (sets) for the FLUID variable.

Version 2

/* REXX ***************************************************************
* Demonstrate how the history of assignments can be kept and shown
* 13.07.2012 Walter Pachl  Rewrite of Version 1 for (my) readability
*   varset.i.varu contains the ith value assigned to var
*   varset.0.varu contains the number of assignments so far
**********************************************************************/
varset.=0                          /*initialize the assignment count */

call varset 'fluid',min(0,-5/2,-1)   ; say 'fluid=' fluid
call varset 'fluid',3.14159          ; say 'fluid=' fluid
call varset 'fluid',3.14159          ; say 'fluid=' fluid
call varset 'fluid',' Santa  Claus'  ; say 'fluid=' fluid
call varset 'FLUID',' Easter Rabbit' ; say 'fluid=' fluid

say 'There were' varset('fluid',,'L'),
    'assignments (sets) for the FLUID variable.'
exit

varset: Procedure Expose varset.
/**********************************************************************
* record values assigned to var (=varu as Rexx is case insensitive)
* Invoke with list<>'' to list the sequence of assigned values
* and return the number of assignments made (using this routine)
**********************************************************************/
  Parse Upper Arg varu              /* name of variable in uppercase */
  Parse arg var,value,list          /*varName, value, optional-List. */

  if list='' then do                /*not list, so set the X variable*/
    z=varset.0.varu+1               /*bump the history count (SETs). */
    varset.z.varu=value             /* ... and store it in "database"*/
    varset.0.varu=z                 /*the new history count          */
    call value var,value            /*now assign the value to var    */
    end
  else Do
    Say ''                          /*show blank line for readability*/
    do i=1 to varset.0.varu         /*list the assignment history    */
      say 'history entry' i "for var" var":" varset.i.varu
      end
    end
  Return varset.0.varu           /*return the number of assignments. */

Ruby

This uses trace_var, which only works for global variables:

foo_hist = []
trace_var(:$foo){|v| foo_hist.unshift(v)}

$foo = "apple"
$foo = "pear"
$foo = "banana"

p foo_hist # => ["banana", "pear", "apple"]

Rust

#[derive(Clone, Debug)]
struct HVar<T> {
    history: Vec<T>,
    current: T,
}

impl<T> HVar<T> {
    fn new(val: T) -> Self {
        HVar {
            history: Vec::new(),
            current: val,
        }
    }

    fn get(&self) -> &T {
        &self.current
    }

    fn set(&mut self, val: T) {
        self.history.push(std::mem::replace(&mut self.current, val));
    }

    fn history(&self) -> (&[T], &T) {
        (&self.history, &self.current)
    }

    fn revert(&mut self) -> Option<T> {
        self.history
            .pop()
            .map(|val| std::mem::replace(&mut self.current, val))
    }
}

fn main() {
    let mut var = HVar::new(0);
    var.set(1);
    var.set(2);
    println!("{:?}", var.history());
    println!("{:?}", var.revert());
    println!("{:?}", var.revert());
    println!("{:?}", var.revert());
    println!("{:?}", var.get());
}
Output:
([0, 1], 2)
Some(2)
Some(1)
None
0

Scala

Scala doesn't have a native support for history variables, but it's quite easy to implement them. The following class uses same conventions as ML's mutable reference cells. (i.e. ! as accessor, and := as mutator.)

class HVar[A](initialValue: A) extends Proxy {
  override def self = !this
  override def toString = "HVar(" + !this + ")"
  
  def history = _history

  private var _history = List(initialValue)
  def unary_! = _history.head
  def :=(newValue: A): Unit = {
    _history = newValue :: _history
  }
  def modify(f: A => A): Unit = {
    _history = f(!this) :: _history
  }
  def undo: A = {
    val v = !this
    _history = _history.tail
    v
  }
}

Usage:

scala> val h = new HVar(3)
h: HVar[Int] = HVar(3)

scala> h := 11

scala> h := 90

scala> !h
res32: Int = 90

scala> h.history
res33: List[Int] = List(90, 11, 3)

scala> h.undo
res34: Int = 90

scala> h.undo
res35: Int = 11

scala> h.undo
res36: Int = 3

SenseTalk

SenseTalk does not have native support for history variables, but here is a simple object that can be instantiated to provide a history:

// HistoryVariable.script
properties
	history: [], -- a list of all historical values
	asTextFormat:"[[the last item of my history]]" -- always display the last value
end properties

to set newValue
	push newValue nested into my history
end set

to rollback
	pop my history
	return it
end rollback

Here is an example how this could be used (note that variables in SenseTalk may hold any type of value):

set x to be a new HistoryVariable

tell x to set "Hello"
put "x is now" && x -- display the current value

tell x to set 88
put "x is now" && x

tell x to set "World"
put "x is now" && x

put "History of x:" && x's history -- non-destructively display the history

tell x to set [9,6,3] -- set it to a list
put "x is now" && x

put "History of x:" && the history of x

put "Rolling back:" && x.rollback -- remove the last value
put "After rollback, x is now" && x
Output:
x is now Hello
x is now 88
x is now World
History of x: ["Hello",88,"World"]
x is now [9,6,3]
History of x: ["Hello",88,"World",[9,6,3]]
Rolling back: [9,6,3]
After rollback, x is now World

Sidef

Implemented as a class:

class HistoryVar(v) {

    has history = []
    has variable = v

    method (value) {
        history << variable
        variable = value
    }

    method to_s {
        "#{variable}"
    }

    method AUTOLOAD(_, name, *args) {
        variable.(name)(args...)
    }
}

var foo = HistoryVar(0)

foo  1
foo  2
foo  foo+3
foo  42

say "History: #{foo.history}"
say "Current value: #{foo}"
Output:
History: [0, 1, 2, 5]
Current value: 42

Smalltalk

Smalltalk doesn't have native support for history variables. It could be implemented using (implementation dependent) tracing facilities, or by changing the code generator (which is part of the library and open for change). The following implementation is portable and in the spirit of the Lisp implementation above, and defines a new "assignment operator":

Object subclass:'HVar'
    instanceVariableNames:'values' 
    classVariableNames:'' 
    poolDictionaries:'' 
    category:'example'.
!

!HVar methodsFor:'accessing'!

<-- value
    (values ifNil:[values := OrderedCollection new]) add:value.
    ^  value
!

value
    ^ values last
!

undo
    values removeLast.
!

history
    ^ history
! !

|x|

x := HVar new.
x <-- 1.
x value.  
x <-- 2.
x <-- (x value + 1).
x value.  
x history.

Swift

Swift does not support history variables. However, you can add a watcher that can track when the variable will change.

var historyOfHistory = [Int]()
var history:Int = 0 {
    willSet {
        historyOfHistory.append(history)
    }
}

history = 2
history = 3
history = 4
println(historyOfHistory)

another approach, using generics: plug this code into a Playground to see the output

Works with: Swift version 2.x+
struct History <T> {
    
    private var _history = [T]()
    var history : [T] {
        return _history
    }
    
    var now : T {
        return history.last!
    }
    
    init(_ firstValue:T) {
        _history = [firstValue]
    }
    
    mutating func set(newValue:T) {
        _history.append(newValue)
    }
    
    mutating func undo() -> T {
        guard _history.count > 1 else { return _history.first! }
        _history.removeLast()
        return _history.last!
    }
}

var h = History("First")
h.set("Next")
h.set("Then")
h.set("Finally")
h.history   // output ["First", "Next", "Then", "Finally"]

h.now       // outputs "Finally"
h.undo()    // outputs "Then"
h.undo()    // outputs "Next"
h.undo()    // outputs "First"
h.undo()    // outputs "First", since it can't roll back any further
h.undo()    // outputs "First"

Tcl

Though Tcl's variables don't have history by default, it can be added easily through the use of traces:

# Define the history machinery
proc histvar {varName operation} {
    upvar 1 $varName v ___history($varName) history
    switch -- $operation {
	start {
	    set history {}
	    if {[info exist v]} {
		lappend history $v
	    }
	    trace add variable v write [list histvar.write $varName]
	    trace add variable v read [list histvar.read $varName]
	}
	list {
	    return $history
	}
	undo {
	    set history [lrange $history 0 end-1]
	}
	stop {
	    unset history
	    trace remove variable v write [list histvar.write $varName]
	    trace remove variable v read [list histvar.read $varName]
	}
    }
}
proc histvar.write {key varName args} {
    upvar 1 $varName v ___history($key) history
    lappend history $v
}
proc histvar.read {key varName args} {
    upvar 1 $varName v ___history($key) history
    set v [lindex $history end]
}

Demonstrating how to use it:

# Enable history for foo
histvar foo start
set foo {a b c d}
set foo 123
set foo "quick brown fox"
puts $foo
puts foo-history=[join [histvar foo list] ", "]
puts $foo
histvar foo undo
puts $foo
histvar foo undo
puts $foo
histvar foo stop
Output:
quick brown fox
foo-history=a b c d, 123, quick brown fox
quick brown fox
123
a b c d

Wren

Translation of: Kotlin

Not built in but we can soon make a suitable class.

class HistoryVariable {
    construct new(initValue) {
        _history = [initValue]
    }

    currentValue { _history[-1] }
    currentValue=(newValue) { _history.add(newValue) }

    showHistory() {
        System.print("The variable's history, oldest values first, is:")
        for (item in _history) System.print(item)
    }
}

var v = HistoryVariable.new(1)
v.currentValue = 2
v.currentValue = 3
v.showHistory()
System.print("\nCurrent value is %(v.currentValue)")
Output:
The variable's history, oldest values first, is:
1
2
3

Current value is 3

zkl

No native support, here is a something that can be done with a class:

class HistoryVar{
   var [private] _v, _history=List(), maxSz;
   fcn init(v,maxEntries=3){ maxSz=maxEntries; set(v) }
   fcn set(v){ 
      _v=v; _history.append(T(Time.Clock.time,v));
      if(_history.len()>maxSz) _history.del(0);
      self
   }
   fcn get(n=0){  // look back into history
      z:=_history.len();
      n=(if(n>=z) 0 else z-n-1);
      _history[n][1] 
   }
   var [proxy] v=fcn{ _v };
   var [proxy] history=
      fcn{ _history.pump(List,fcn([(t,v)]){ T(Time.Date.ctime(t),v) }) };
   fcn __opAdd(x){ set(_v + x); self }
}
hv:=HistoryVar(123);
hv+4;
hv.set("Shuttle prepared for liftoff");
hv+": orbit achived";
hv.history.concat("\n").println();
hv.get(3).println("<-- value two changes ago");
Output:
L("Thu Oct 13 13:48:37 2016",127)
L("Thu Oct 13 13:48:37 2016","Shuttle prepared for liftoff")
L("Thu Oct 13 13:48:37 2016","Shuttle prepared for liftoff: orbit achived")
127<-- value two changes ago