View Problem
OOP

Implement and use an Interface

Create a Serializable interface consisting of 'save' and 'restore' methods, each of which:

* Accept a stream or handle or descriptor argument for the source or destination
* Save to destination or restore from source the properties or data members of the implementing class (restrict yourself to the primitive types 'int' and 'string')

Next, create a Person class which has 'name' and 'age' properties or data members and implements this interface. Instantiate a Person object, save it to a serial stream, and instantiate a new Person object by restoring it from the serial stream.
ExpandDiskEdit
clojure
(defn person [name age]
{:name name :age age})

(defn show [p]
(println (format "Name=%s Age=%d" (:name p) (:age p))))

(defn save [p filename]
(with-out-writer filename (pr p)))

(defn restore [filename]
(read (PushbackReader. (reader filename))))

(let [p (person "Ken" 38)]
(show p)
(save p *person-fn*))

(let [ser-p (restore *person-fn*)]
(show ser-p))
ExpandDiskEdit
cpp
struct person
{
person(){}
person(const string &name, int age) : name_(name), age_(age) {}

string name_;
int age_;

template<typename Archive>
void serialize(Archive &ar, const unsigned int version) {
ar & name_ & age_;
}
};


int main()
{
const char *fn = "filename.txt";

person k("Ken", 38);
{
ofstream ofs(fn);
archive::text_oarchive oa(ofs);
oa << k;
}

person restored_person;
{
ifstream ifs(fn);
archive::text_iarchive ia(ifs);
ia >> restored_person;
}

cout << "Name : " << restored_person.name_ << endl
<< "Age : " << restored_person.age_ << endl;
}
DiskEdit
fantom
@Serializable
class Person
{
Str name
Int age
new make(|This| f) { f(this) }
}

person := Person() { name="Tom Bones"; age=23 }
File(`tommy.dump`).out.writeObj(person).close
Person tom := File(`tommy.dump`).in.readObj
DiskEdit
fsharp
// Since everyone else is using built-in functionality instead of
// defining an interface as required, I won't buck the trend.
// Maybe this problem should be named "Use serialization features" instead
// of "Implement and use an Interface"

open System
open System.IO
open System.Runtime.Serialization.Formatters.Binary

[<Serializable>]
type Person(name:string, age:int) =
member this.Name = name
member this.Age = age

let serialize x =
use ms = new MemoryStream()
let bf = new BinaryFormatter()
bf.Serialize(ms, x)
ms.ToArray()

let deserialize<'a> bytes =
use ms = new MemoryStream(bytes:byte[])
let bf = new BinaryFormatter()
bf.Deserialize(ms) :?> 'a

let before = Person("Joel", 35)
let bytes = serialize before
let after = deserialize<Person> bytes

printfn "Before: %s, %i" before.Name before.Age
printfn "After: %s, %i" after.Name after.Age
DiskEdit
groovy
// Built-in functionality but with slightly different names. Showing usage:
class Person implements Serializable { String name; int age }
p1 = new Person(name:'John', age:21)
p2 = null
output = new ByteArrayOutputStream() // or FileOutputStream, etc.
output.withObjectOutputStream { oos -> oos << p1 }
input = new ByteArrayInputStream(output.toByteArray())
input.withObjectInputStream(getClass().classLoader){ ois -> p2 = ois.readObject() }
assert p2.name == 'John'
assert p2.age == 21
DiskEdit
haskell
import Data.Binary
import Control.Monad (liftM2)

data People = People { name :: String, age :: Integer }
deriving (Eq, Show)

class Serializable a where
save :: FilePath -> a -> IO ()
restore :: FilePath -> IO a

instance Serializable People where
save = encodeFile
restore = decodeFile

instance Binary People where
put (People n a) = put n >> put a
get = liftM2 People get get

main = do let fp = "people.dat"
p = People { name = "Joe", age = 24 }
save fp p
p' <- restore fp
print (p' :: People)
ExpandDiskEdit
java 1.3 and above
// Serialization to a file
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean equals(Object obj) {
if(obj == this) return true;
if(obj instanceof Person) {
Person p = (Person) obj;
return (p.getName().equals(this.getName())
& p.getAge() == this.getAge());
}
return false;
}
public String toString() {
return "Name: " + name + ", age: " + age;
}
}
Person person = new Person();
person.setName("Gaylord Focker");
person.setAge(21);

try {
File file = new File("ser.obj");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(person);
oos.close();
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Person deserializedPerson = (Person) ois.readObject();
ois.close();
System.out.println(deserializedPerson);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
DiskEdit
ocaml
(* in OCaml, interfaces are class types, and have nothing to do with inheritance,
so I'm not sure what's the correct answer to this problem (if any) *)

class type serializable =
object
method save: out_channel -> unit
method restore: in_channel -> unit
end

class person name age =
object
val mutable my_name = name
val mutable my_age = age
method save oc = output_value oc my_name; output_value oc my_age
method restore ic = my_name <- input_value ic; my_age <- input_value ic
method print = Printf.printf "I'm %s, %d\n" my_name my_age
end

let transfer (o1: serializable) (o2: serializable) =
let temp_filename = "_person" in
let backing_store_save = open_out_bin temp_filename in
o1#save backing_store_save;
close_out backing_store_save;

let backing_store_restore = open_in_bin temp_filename in
o2#restore backing_store_restore;
close_in backing_store_restore


let o = new person "john" 42 in
let o2 = new person "nobody" 0 in
transfer (o :> serializable) (o2 :> serializable);
o2#print
DiskEdit
perl 5
package Person;

use Moose;
use MooseX::Storage;
with Storage('format' => 'JSON', 'io' => 'File');

has 'name' => (is => 'rw', isa => 'Str');
has 'age' => (is => 'rw', isa => 'Int');

1;

Person->new( name => 'David B.', age => 28)->store('person.json');

my $p = Person->load('person.json');
DiskEdit
perl
{
package Serializable;
use Role::Basic;
use Storable qw'store_fd retrieve_fd';
use Scalar::Util 'blessed';
use IO::Handle;
use Carp;

sub save {
my $self = shift;
my $fd = shift or croak 'Needs target file handle';
$DB::single = (1);
store_fd($self, $fd);
}

sub restore {
my $class = shift;
my $fd = shift or croak 'Needs source file handle';
my $self = retrieve_fd( $fd );
bless $self, $class
}

}
{
package Person;
use Role::Basic 'with';
use Scalar::Util 'looks_like_number';
use Carp;

with 'Serializable';

sub new {
my $class = shift;
croak 'Invalid parameters' if (@_ % 2);
%parameters = @_;

do {
croak "Missing $_" unless defined $parameters{$_}
} for qw/name age/;
croak 'Invalid age' unless looks_like_number($parameters{age});
bless \%parameters, $class
}
sub name {
$self{name}
}
sub age {
$self{age}
}
}

use IO::Handle;
my $p1 = Person->new(age => 42, name => 'Milly Fogg');
open my $fh, '+>', 'person.store';
$p1->save( $fh );
seek $fh, 0, SEEK_SET;
my $p2 = Person->restore( $fh );
ExpandDiskEdit
php 5 (tested in 5.3)
class Person implements Serializable {
private $name;
private $age;
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}
public function serialize() {
return serialize(array($this->name, $this->age));
}
public function unserialize($serialized) {
list($this->name, $this->age) = unserialize($serialized);
}
public function getData() {
return array($this->name, $this->age);
}
}

$obj = new Person('Gaylord Focker', 21);
file_put_contents('person.dump', serialize($obj));

$newobj = unserialize(file_get_contents('person.dump'));

var_dump($newobj->getData());
DiskEdit
python 2.6
import pickle

class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return "Name: {name}, age: {age}".format(name=self.name, age=self.age)


person = Person("Gaylord Focker", 21)
with open("person.pickle", "wb") as outstream:
pickle.dump(person, outstream)
with open("person.pickle", "rb") as instream:
deserialized_person = pickle.load(instream)
print(deserialized_person)
DiskEdit
ruby
class Person
def initialize(name, age)
@name, @age = name, age
end
end

tom = Person.new("Tom Bones", 23)

File.open('tommy.dump', 'w+') {|f| f.write(Marshal.dump(tommy)) }
toms_clone = Marshal.load(File.read('tommy.dump'))
ExpandDiskEdit
scala
class Person (var name: String, var age: Int) extends Serializable

val p1 = new Person("John", 21)
val output = new ByteArrayOutputStream()
val oos = new ObjectOutputStream(output)
oos.writeObject(p1)
oos.flush
oos.close

val input = new ByteArrayInputStream(output.toByteArray())
val ois = new ObjectInputStream(input)
val p2 = ois.readObject().asInstanceOf[Person]

assert(p2.name == "John")
assert(p2.age == 21)

Submit a new solution for clojure, cpp, fantom, fsharp ...