History variables: Difference between revisions

m
imported>Arakov
 
(16 intermediate revisions by 12 users not shown)
Line 23:
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}}==
Line 37 ⟶ 65:
Specification:
 
<langsyntaxhighlight Adalang="ada">private with Ada.Containers.Indefinite_Vectors;
generic
type Item_Type (<>) is private;
Line 70 ⟶ 98:
History: Vectors.Vector;
end record;
end History_Variables;</langsyntaxhighlight>
 
The implementation of "History_Variables":
 
<langsyntaxhighlight Adalang="ada">package body History_Variables is
 
-- set and get
Line 108 ⟶ 136:
end Undo;
 
end History_Variables;</langsyntaxhighlight>
 
 
===Sample 1: The History of an Integer Variable===
 
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO, History_Variables;
 
procedure Test_History is
Line 144 ⟶ 172:
Ada.Text_IO.Put_Line(Integer'Image(Sum));
 
end Test_History;</langsyntaxhighlight>
 
{{out}}
Line 153 ⟶ 181:
===Sample 2: The History of a String===
 
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO, History_Variables;
 
procedure Test_History is
Line 184 ⟶ 212:
Ada.Text_IO.Put_Line(Integer'Image(Sum));
 
end Test_History;</langsyntaxhighlight>
 
{{out}}
Line 193 ⟶ 221:
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.
<langsyntaxhighlight lang="algolw">begin
% implements integer history variables %
% similar history types could be defined for other types of variable %
Line 227 ⟶ 255:
write( "Sum of the historic values: ", s )
end
end.</langsyntaxhighlight>
{{out}}
<pre>
Line 233 ⟶ 261:
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):
<langsyntaxhighlight lang="java">public class HistoryVariable
{
private Object value;
Line 265 ⟶ 357:
{
}
}</langsyntaxhighlight>
Aspect (HistoryHandling.aj):
<langsyntaxhighlight lang="java">import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
Line 309 ⟶ 401:
 
private Map<HistoryVariable, Deque<Object>> history = new HashMap<>();
}</langsyntaxhighlight>
Usage:
<langsyntaxhighlight lang="java">public final class Main
{
public static void main(final String[] args)
Line 327 ⟶ 419:
System.out.println(hv.toString());
}
}</langsyntaxhighlight>
 
{{out}}
Line 341 ⟶ 433:
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}}
<langsyntaxhighlight lang="ahk">HV := new HistoryVariable
HV.var := 1
HV.var := 2
Line 355 ⟶ 447:
Return this[1]
}
}</langsyntaxhighlight>
 
=={{header|C sharp}}==
<langsyntaxhighlight lang="c sharp">using System;
using System.Collections;
using System.Collections.Generic;
Line 426 ⟶ 518:
}
}
}</langsyntaxhighlight>
 
{{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>
 
Line 436 ⟶ 603:
via a watcher function that can track changes on a variable.
 
<langsyntaxhighlight 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>
</lang>
 
{{out|Sample Output}}
Line 463 ⟶ 630:
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.
 
<langsyntaxhighlight lang="lisp">(defmacro make-hvar (value)
`(list ,value))
 
Line 486 ⟶ 653:
(undo-hvar v)
(format t "Restored value = ~a~%" (get-hvar v)))
</syntaxhighlight>
</lang>
{{out}}
<pre>Initial value = 1
Line 496 ⟶ 663:
D does not have history variables. The following implementation provides a generic HistoryVariable that protects the historical values by defining them as 'const'.
 
<langsyntaxhighlight lang="d">import std.stdio, std.array, std.string, std.datetime, std.traits;
 
/// A history variable.
Line 558 ⟶ 725:
s = "goodby";
writefln("%(%s\n%)", s.history);
}</langsyntaxhighlight>
{{out|Sample Output}}
<pre>2013-Jan-19 23:04:55.1660302; 1
Line 568 ⟶ 735:
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.
<langsyntaxhighlight lang="lisp">
(define-syntax-rule (make-h-var name) (define name (stack (gensym))))
(define-syntax-rule (h-get name) (stack-top name))
Line 594 ⟶ 889:
(h-undo x) → 42
(h-undo x) → ❌ error: no more values x
</syntaxhighlight>
</lang>
 
=={{header|Elena}}==
ELENA 56.0x :
<langsyntaxhighlight lang="elena">import extensions;
import system'collections;
import system'routines;
Line 649 ⟶ 944:
console.printLine(o);
o.forEach:(printingLn);
o.undo().undo().undo();
console.printLine(o.Value ?? "nil")
}</langsyntaxhighlight>
{{out}}
<pre>
Line 685 ⟶ 980:
 
=={{header|Factor}}==
<langsyntaxhighlight lang="factor">USING: accessors combinators formatting kernel models.history ;
 
1 <history> {
Line 696 ⟶ 991:
[ go-back ]
[ value>> "Restored value: %u\n" printf ]
} cleave</langsyntaxhighlight>
{{out}}
<pre>
Line 706 ⟶ 1,001:
=={{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.
<langsyntaxhighlight 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 ! ;</langsyntaxhighlight>
 
A sample session:
Line 731 ⟶ 1,026:
=={{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.
<langsyntaxhighlight lang="go">package main
 
import (
Line 843 ⟶ 1,138:
fmt.Println(rv)
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 861 ⟶ 1,156:
There are no native Haskell history variables, but they are simple to implement.
 
<langsyntaxhighlight lang="haskell">import Data.IORef
 
newtype HVar a = HVar (IORef [a])
Line 892 ⟶ 1,187:
undoHVar var
undoHVar var
undoHVar var</langsyntaxhighlight>
 
=={{header|J}}==
Line 898 ⟶ 1,193:
J does not natively support "history variables", but the functionality is easy to add:
 
<langsyntaxhighlight lang="j">varref_hist_=:'VAR','_hist_',~]
set_hist_=:4 :0
V=.varref x
Line 909 ⟶ 1,204:
)
length_hist_=: #@getall
get_hist_=: _1 {:: getall</langsyntaxhighlight>
 
Example use:
 
<langsyntaxhighlight lang="j"> 'x' set_hist_ 9
9
'x' set_hist_ 10
Line 926 ⟶ 1,221:
┌─┬──┬──┐
│9│10│11│
└─┴──┴──┘</langsyntaxhighlight>
 
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 937 ⟶ 1,232:
Java does not support history variables, but they are easy to implement using the lists that come with Java's Collections framework.
 
==={{header|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).
<langsyntaxhighlight Javalang="java">import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
Line 1,012 ⟶ 1,307:
}
}
</syntaxhighlight>
</lang>
Test Program:
<langsyntaxhighlight Javalang="java">public class TestIntegerWithHistory {
 
public static void main(String[] args) {
Line 1,038 ⟶ 1,333:
 
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,054 ⟶ 1,349:
</pre>
 
==={{header|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).
<lang java></lang>
Test Program using a "String with History":
<langsyntaxhighlight lang="java">import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
Line 1,134 ⟶ 1,428:
}
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,152 ⟶ 1,446:
=={{header|Julia}}==
Julia currently does not support overloading the assignment "=" operator.
<langsyntaxhighlight Julialang="julia">mutable struct Historied
num::Number
history::Vector{Number}
Line 1,167 ⟶ 1,461:
 
println("Past history of variable x: $(x.history). Current value is $(x.num)")
</langsyntaxhighlight>{{output}}<pre>Past history of variable x: Number[1, 3, 5]. Current value is 4</pre>
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">// version 1.1.4
 
class HistoryVariable<T>(initialValue: T) {
Line 1,197 ⟶ 1,491:
v.showHistory()
println("\nCurrentvalue is ${v.currentValue}")
}</langsyntaxhighlight>
 
{{out}}
Line 1,211 ⟶ 1,505:
=={{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===
<lang lua>-- History variables in Lua 6/12/2020 db
<syntaxhighlight lang="lua">-- History variables in Lua 6/12/2020 db
local HistoryVariable = {
history = {},
new = function(self)
return setmetatable({history={}},self)
end,
get = function(self)
Line 1,241 ⟶ 1,535:
hv:undo(); print("undo() to:", hv:get())
hv:undo(); print("undo() to:", hv:get())
hv:undo(); print("undo() to:", hv:get())</langsyntaxhighlight>
{{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
Line 1,257 ⟶ 1,597:
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">
<lang M2000 Interpreter>
Flush ' empty curtrent stack
\\ a is a pointer to a new stack object
Line 1,296 ⟶ 1,636:
b=stackitem(z, 2)
Print stackitem(b, 4)=1000
</syntaxhighlight>
</lang>
 
So now lets see the code:
 
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module CheckHistoryVariables {
Class History {
Line 1,480 ⟶ 1,820:
}
CheckStringHistoryVariables
</syntaxhighlight>
</lang>
 
=={{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}}==
<langsyntaxhighlight lang="oberon2">
MODULE HVar;
IMPORT Out, Conv;
Line 1,663 ⟶ 2,069:
ShowVal(history.Undo());
END HVar.
</syntaxhighlight>
</lang>
 
=={{header|OCaml}}==
The easiest solution is to use the Stack module coming with OCaml's standard library:
<langsyntaxhighlight lang="ocaml">
open Stack
(* The following line is only for convenience when typing code *)
Line 1,684 ⟶ 2,090:
hs |> H.pop |> Printf.printf "%d\n";
hs |> H.pop |> Printf.printf "%d\n"
</syntaxhighlight>
</lang>
 
{{out}}
Line 1,698 ⟶ 2,104:
=={{header|OxygenBasic}}==
Simple history class for fixed length types that do not contain volatile pointer members.
<langsyntaxhighlight lang="oxygenbasic">
'============
class History
Line 1,757 ⟶ 2,163:
 
del hv
</syntaxhighlight>
</lang>
 
=={{header|PARI/GP}}==
<langsyntaxhighlight lang="parigp">default(histsize, 1000) \\ or some other positive number to suit
1+7
sin(Pi)
Line 1,769 ⟶ 2,175:
\a2
\a3
[%1, %2, %3] \\ or any other command using these values</langsyntaxhighlight>
 
=={{header|Peloton}}==
<langsyntaxhighlight lang="sgml">Turn history on <@ DEFHST>__on</@>
Notify Protium we are interested in the variable mv
<@ DEFHST>mv</@>
Line 1,782 ⟶ 2,188:
Undo once: <@ ACTUNDVAR>mv</@><@ SAYVAR>mv</@>
Undo twice: <@ ACTUNDVAR>mv</@><@ SAYVAR>mv</@>
Turn history off <@ DEFHST>__off</@></langsyntaxhighlight>
 
Same code, Simplified Chinese dialect
<langsyntaxhighlight lang="sgml">Turn history on <# 定义变量史>__on</#>
Notify Protium we are interested in the variable mv
<# 定义变量史>mv</#>
Line 1,795 ⟶ 2,201:
Undo once: <# 运行撤消变量>mv</#><# 显示变量>mv</#>
Undo twice: <# 运行撤消变量>mv</#><# 显示变量>mv</#>
Turn history off <# 定义变量史>__off</#> </langsyntaxhighlight>
 
{{out}}
Line 1,813 ⟶ 2,219:
=={{header|Perl}}==
Implemented via tie (and what's the usefulness of this?)
<langsyntaxhighlight Perllang="perl">package History;
 
sub TIESCALAR {
Line 1,852 ⟶ 2,258:
 
History::off($x);
print "\$x is: $x\n";</langsyntaxhighlight>
{{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</langsyntaxhighlight>
 
=={{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">-->
<lang Phix>sequence history = {}
<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>
type hvt(object o)
history = append(history,o)
<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>
return true
<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>
end type
<span style="color: #008080;">return</span> <span style="color: #004600;">true</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">type</span>
hvt test = 1
test = 2
<span style="color: #000000;">hvt</span> <span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
test = 3
<span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span>
?{"current",test}
<span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">3</span>
?{"history",history}</lang>
<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>
Line 1,879 ⟶ 2,288:
{"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)-->
<lang Phix>-- history.e
<span style="color: #000080;font-style:italic;">-- history.e</span>
sequence histories = {}
<span style="color: #004080;">sequence</span> <span style="color: #000000;">histories</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
 
global function new_history_id(object v)
<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>
histories = append(histories,{v})
<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>
return length(histories)
<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>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
 
global procedure set_hv(integer hv, object v)
<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>
histories[hv] = append(histories[hv],v)
<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>
end procedure
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
 
global function get_hv(integer hv)
<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>
return histories[hv][$]
<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>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
 
global function get_hv_full_history(integer hv)
<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>
return histories[hv]
<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>
end function</lang>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<!--</syntaxhighlight>-->
And use it like this
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>include history.e
<span style="color: #008080;">include</span> <span style="color: #000000;">history</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
 
constant test2 = new_history_id(1)
<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>
set_hv(test2, 2)
<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>
set_hv(test2, 3)
<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>
?{"current",get_hv(test2)}
<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>
?{"history",get_hv_full_history(test2)}</lang>
<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}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de setH ("Var" Val)
(when (val "Var")
(with "Var"
Line 1,918 ⟶ 2,331:
 
(de restoreH ("Var")
(set "Var" (pop (prop "Var" 'history))) )</langsyntaxhighlight>
Test:
<pre>: (setH 'A "Hello world")
Line 1,948 ⟶ 2,361:
 
=={{header|PL/I}}==
<syntaxhighlight lang="pl/i">
<lang PL/I>
declare t float controlled;
 
Line 1,958 ⟶ 2,371:
put (t); free t;
end;
</syntaxhighlight>
</lang>
 
=={{header|PureBasic}}==
<langsyntaxhighlight PureBasiclang="purebasic">; integer history variable
 
Structure historyint
Line 2,010 ⟶ 2,423:
Debug "undo, x = "+Str(x\value())
Next
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,029 ⟶ 2,442:
=={{header|Python}}==
 
<langsyntaxhighlight Pythonlang="python">import sys
 
HIST = {}
Line 2,062 ⟶ 2,475:
 
sys.settrace(trace)
main()</langsyntaxhighlight>
{{out}}<syntaxhighlight lang="text">c: 4 -> undo x3 -> 1
HIST: {'a': [10, 20], 'i': [0, 1, 2, 3, 4], 'c': [0, 1], 'name': ['c']}</langsyntaxhighlight>
 
 
=={{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}}==
Line 2,070 ⟶ 2,513:
Racket does not come with history variables, but they can be provided as a library as follows:
 
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 2,100 ⟶ 2,543:
(hvar-undo! hv)
(check-equal? (hvar-current hv) 0)
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2018.03}}
<syntaxhighlight lang="raku" perl6line>class HistoryVar {
has @.history;
has $!var handles <Str gist FETCH Numeric>;
Line 2,122 ⟶ 2,565:
 
.say for foo.history;
say "Current value: {foo}";</langsyntaxhighlight>
{{out}}
<pre>[Instant:1523396079.685629 (Any)]
Line 2,136 ⟶ 2,579:
<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.
<langsyntaxhighlight 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
Line 2,157 ⟶ 2,600:
say 'history entry' ?j "for var" ?z":" varSet!.?J.?x
end /*?j*/
return ?j-1 /*return the number of assignments. */</langsyntaxhighlight>
'''output'''
<pre>
Line 2,171 ⟶ 2,614:
 
===Version 2===
<langsyntaxhighlight lang="rexx">
/* REXX ***************************************************************
* Demonstrate how the history of assignments can be kept and shown
Line 2,212 ⟶ 2,655:
end
Return varset.0.varu /*return the number of assignments. */
</syntaxhighlight>
</lang>
 
=={{header|Ruby}}==
This uses trace_var, which only works for global variables:
<langsyntaxhighlight lang="ruby">foo_hist = []
trace_var(:$foo){|v| foo_hist.unshift(v)}
 
Line 2,224 ⟶ 2,667:
 
p foo_hist # => ["banana", "pear", "apple"]
</syntaxhighlight>
</lang>
 
=={{header|Rust}}==
<langsyntaxhighlight Rustlang="rust">#[derive(Clone, Debug)]
struct HVar<T> {
history: Vec<T>,
Line 2,269 ⟶ 2,712:
println!("{:?}", var.revert());
println!("{:?}", var.get());
}</langsyntaxhighlight>
{{out}}
<pre>([0, 1], 2)
Line 2,279 ⟶ 2,722:
=={{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.)
<langsyntaxhighlight lang="scala">class HVar[A](initialValue: A) extends Proxy {
override def self = !this
override def toString = "HVar(" + !this + ")"
Line 2,298 ⟶ 2,741:
v
}
}</langsyntaxhighlight>
Usage:
<langsyntaxhighlight lang="scala">scala> val h = new HVar(3)
h: HVar[Int] = HVar(3)
 
Line 2,320 ⟶ 2,763:
 
scala> h.undo
res36: Int = 3</langsyntaxhighlight>
 
=={{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:
<langsyntaxhighlight lang="ruby">class HistoryVar(v) {
 
has history = []
Line 2,351 ⟶ 2,845:
 
say "History: #{foo.history}"
say "Current value: #{foo}"</langsyntaxhighlight>
{{out}}
<pre>
Line 2,361 ⟶ 2,855:
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":
<langsyntaxhighlight lang="smalltalk">Object subclass:'HVar'
instanceVariableNames:'values'
classVariableNames:''
Line 2,396 ⟶ 2,890:
x value.
x history.
</syntaxhighlight>
</lang>
 
=={{header|Swift}}==
Swift does not support history variables. However, you can add a watcher that can track when the variable will change.
<langsyntaxhighlight Swiftlang="swift">var historyOfHistory = [Int]()
var history:Int = 0 {
willSet {
Line 2,411 ⟶ 2,905:
history = 4
println(historyOfHistory)
</syntaxhighlight>
</lang>
 
another approach, using generics:
plug this code into a Playground to see the output
{{works with|Swift|2.x+}}
<langsyntaxhighlight lang="swift">
 
struct History <T> {
Line 2,457 ⟶ 2,951:
h.undo() // outputs "First"
 
</syntaxhighlight>
</lang>
 
=={{header|Tcl}}==
Though Tcl's variables don't have history by default, it can be added easily through the use of traces:
<langsyntaxhighlight lang="tcl"># Define the history machinery
proc histvar {varName operation} {
upvar 1 $varName v ___history($varName) history
Line 2,493 ⟶ 2,987:
upvar 1 $varName v ___history($key) history
set v [lindex $history end]
}</langsyntaxhighlight>
Demonstrating how to use it:
<langsyntaxhighlight lang="tcl"># Enable history for foo
histvar foo start
set foo {a b c d}
Line 2,507 ⟶ 3,001:
histvar foo undo
puts $foo
histvar foo stop</langsyntaxhighlight>
{{out}}
<pre>
Line 2,520 ⟶ 3,014:
{{trans|Kotlin}}
Not built in but we can soon make a suitable class.
<langsyntaxhighlight ecmascriptlang="wren">class HistoryVariable {
construct new(initValue) {
_history = [initValue]
Line 2,538 ⟶ 3,032:
v.currentValue = 3
v.showHistory()
System.print("\nCurrent value is %(v.currentValue)")</langsyntaxhighlight>
 
{{out}}
Line 2,552 ⟶ 3,046:
=={{header|zkl}}==
No native support, here is a something that can be done with a class:
<langsyntaxhighlight lang="zkl">class HistoryVar{
var [private] _v, _history=List(), maxSz;
fcn init(v,maxEntries=3){ maxSz=maxEntries; set(v) }
Line 2,569 ⟶ 3,063:
fcn{ _history.pump(List,fcn([(t,v)]){ T(Time.Date.ctime(t),v) }) };
fcn __opAdd(x){ set(_v + x); self }
}</langsyntaxhighlight>
<langsyntaxhighlight 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");</langsyntaxhighlight>
{{out}}
<pre>
Anonymous user