Create an object whose state changes on assignment

31

3

I find it deeply weird that this is possible in Ruby (I won't immediately say how):

obj = #code redacted

print obj.state # Some value.

LValue = obj

print obj.state # Different value!

Your challenge is to create code roughly of this form. Create an object and assign it to a variable. It should have some defined attribute (or deterministic, idempotent method) like state above, that changes after the object is assigned to a new identifier (LValue above), even if you still use the old identifier (obj above) to refer to it.

Edit for emphasis: state or the equivalent must be idempotent, so creating an accessor that modifies the value, or for any other reason returns different results when called several times in a row, isn't a valid solution. Or, more simply, it has to be the assignment that changes the state.

Any language with assignment is eligible, although there are probably some where there's no fully legitimate solution. I'll post my Ruby answer if nobody else gets it after a few days, and accept highest-voted answers on a rolling basis.

histocrat

Posted 2014-06-04T15:11:50.157

Reputation: 20 600

Would destructive alterations to the object itself? EmacsLisp: (setq a (list "val")) (setq b (nconc a "val2")) for example. a ends up evaluating as ("val" . "val2") at that point. – Jonathan Leech-Pepin – 2015-11-04T22:38:18.983

It's a popularity contest, but to me returning the refcount is in the spirit of the challenge, but putting a destructive operation on the right hand side is not -- in your example, it's the nconc that's performing the mutation, not the setq (if I understand correctly). – histocrat – 2015-11-04T23:18:51.537

Must the LValue = obj line be required for state to actually change? (I could just make a property in C# that increments every time you get it) – Tim S. – 2014-06-04T20:27:01.423

2Yes, that's what I intended by saying the method needed to be idempotent. I'll edit to make that clearer. – histocrat – 2014-06-04T20:33:56.987

Ok, thanks. I must've glossed over that part. – Tim S. – 2014-06-04T20:36:20.483

4Would simply returning the refcount of the object work? – Nick T – 2014-06-05T22:51:49.133

Answers

30

C++

This is trivial using the right tools.

#include <iostream>

using namespace std;

class Obj {
public:
   int state;

   Obj& operator= (Obj& foo) {
      foo.state++;
      this->state = foo.state - 2;
      return *this;
   }
};

int main() {
   Obj a, b, c, d;
   a.state = 3;
   b.state = 4;

   cout << a.state << " " << b.state << "\n";

   c = a;
   d = b;

   cout << a.state << " " << b.state << " " << c.state << " " << d.state << "\n";

   return 0;
}

Output:

3 4
4 5 2 3

marinus

Posted 2014-06-04T15:11:50.157

Reputation: 30 224

12The moment I saw the title, I knew someone would do operator overloading. It's the obvious way. Have an upvote. – None – 2014-06-04T16:09:55.067

17

PHP (debug build, >= 5.4)

We use refcount of the object in a getter. (So, by the assignment, refcount increases and value changes)

class State {
    public function __get($arg) {
        ob_start();
        debug_zval_dump($this); // e.g. "object(State)#1 (0) refcount(6)"
        return ob_get_clean()[29];
    }
}

$obj = new State;
var_dump($obj->state);
$a = $obj;
var_dump($obj->state);

bwoebi

Posted 2014-06-04T15:11:50.157

Reputation: 1 721

14

C#

Two simple options:

class Obj
{
    public int state;
    public static implicit operator int(Obj o)
    {
        return o.state++;
    }
}

static int LValueI;
static Obj LValueM { set { value.state++; } }
static void Main()
{
    var obj = new Obj { state = 1 };
    LValueI = obj;
    Console.WriteLine(obj.state); //2, caused by the implicit cast.

    LValueM = obj;
    Console.WriteLine(obj.state); //3, caused by the property setter.
    Console.ReadLine();
}

Or we could simply write to the same memory:

[StructLayoutAttribute(LayoutKind.Explicit)]
class Program
{
    [FieldOffset(0)]
    int state = 1;
    [FieldOffset(1)]
    int LValue;

    void Test()
    {
        var obj = this;

        Console.WriteLine(state);  //1
        LValue = state;
        Console.WriteLine(state);  //257
        Console.ReadLine();
    }
    static void Main() { new Program().Test(); }
}

NPSF3000

Posted 2014-06-04T15:11:50.157

Reputation: 374

12

TeX, much shorter than other answers here

\setbox0=\hbox{Hello world!} % Put stuff in the box 0.
\message{\the\wd0}           % Print the width of the box => non-zero
\setbox2=\box0               % Put the box instead in box 2.
\message{\the\wd0}           % Now box 0 is void, hence has zero width.

As a typesetting system, TeX has a "box" type, which contains typeset material. Since the most common use case is to move this material around, split it, etc, rather than making copies of it, boxes are normally deleted when used (or rather, "box" variables are pointers and only one pointer at a time can point to an actual box in memory). No need for any magic.

Bruno Le Floch

Posted 2014-06-04T15:11:50.157

Reputation: 1 181

8

C++11 (So you guys have forgotten about unique_ptr/shared_ptr :-) )

#include <iostream>
#include <memory>
using namespace std;
int main() {
    std::unique_ptr<int> u1(new int(0)), u2;
    std::shared_ptr<int> s1 = std::make_shared<int>(0), s2;
    std::cout<<u1.get()<<" "<<u2.get()<<" "<<std::endl;
    std::cout<<s1.use_count()<<" "<<s2.use_count()<<" "<<std::endl;
    u2 = std::move(u1);
    s2 = s1;
    std::cout<<u1.get()<<" "<<u2.get()<<" "<<std::endl;
    std::cout<<s1.use_count()<<" "<<s2.use_count()<<" "<<std::endl;
   return 0;
}

Abhijit

Posted 2014-06-04T15:11:50.157

Reputation: 2 841

7

Fortran 03

This is somewhat similar to Hugo's D answer, but is a little more hidden (partly because who the #$%^ knows Object Oriented Fortran)?

module objects
   implicit none

   type ObjDef
      integer :: state
    contains
      procedure :: initObject
      procedure :: printObject
      procedure :: setNew
   end type
 contains
   subroutine initObject(this)
     class(ObjDef) :: this
     this%state = this%state + 1
   end subroutine initObject

   subroutine printObject(this)
     class(ObjDef) :: this
     print '(a,i0)',"this%state = ",this%state
   end subroutine printObject

   subroutine setNew(this,that)
     class(ObjDef) :: this,that
     that%state = this%state
   end subroutine setNew

end module objects

program objectChange
   use objects
   type(ObjDef) :: a,b

   call initObject(a)
   call printObject(a)
   call b%setNew(a)
   call printObject(a)
end program objectChange

The output is

this%state = 1
this%state = 0

If you can figure out what happened, bonus points to you! If not:

When calling the procedure setNew in the form call b%setNew(a), b is implicitly the first argument, not the second.

Kyle Kanos

Posted 2014-06-04T15:11:50.157

Reputation: 4 270

7

PowerShell

This creates an object whose state property is the names of the variables that point to the object.

$a = @{}| Add-Member -MemberType:16 -PassThru state -Value {
        (gv|?{$this -eq $_.Value}|%{$_.Name}) -join ','} 

'Before: ' + $a.state
$b = $a
'After: ' + $a.state

Output

Before: a,this
After: a,b,this

Note: This doesn't work if the assignment happens in a child scope.

'Before: ' + $a.state
&{$b = $a}
'After: ' + $a.state

Outputs

Before: a,this
After: a,this

Rynant

Posted 2014-06-04T15:11:50.157

Reputation: 2 353

Get-Variable is smart! – mazzy – 2018-12-19T10:04:06.463

5

Perl 5

Here's one way to do it in Perl:

package Magic {
    sub new { bless {state => 1} }
    use overload '""' => sub { $_[0]{state}++ };
}
use feature 'say';

my $obj = new Magic;
say $obj->{state};
substr($_, 0) = $obj;
say $obj->{state};

This outputs:

1
2

Explanation:

This is a straightforward application of overloading. Specifically, I overload the string conversion operator "", which gets called when the overloaded object is assigned to substr() (which, yes, is a legal lvalue in Perl).

There are also plenty of special variables in Perl which stringify anything assigned to them. For example, the following also works:

my $obj = new Magic;
say $obj->{state};
$0 = $obj;
say $obj->{state};

Alternative solution

Here's another way to it:

package Magic {
    use Devel::Peek 'SvREFCNT';
    sub new { bless \my $foo }
    sub state { SvREFCNT ${$_[0]} }
}
use feature 'say';

my $obj = new Magic;
say $obj->state;
my $other = $obj;
say $obj->state;

Here, state is a method (we could make it an attribute with further tie / overload shenanigans, but that would complicate things) that literally counts the number of references to the object. Thus, unlike in the first solution, you actually have to assign $obj to a normal variable that can hold an object reference to make the state change.

Ilmari Karonen

Posted 2014-06-04T15:11:50.157

Reputation: 19 513

5

JavaScript

Ok, so i made a shorter version that works as SSCCE, but does no longer try to parse JavaScript properly, so the reference counting might not work when put inside a more complex script.

(function run () {
    var lineOne = getLine (1), a, b, x, y, z;
    var x = {
        get state () {
            var x=/([a-z]+)\s*=\s*([a-z]+)/,c;
            return 1 + Object.keys (c = run.toString ().split ('\n').slice (0,getLine (2)).filter (function (a) {return (x.test (a))}).reduce (function (a,b,c,d) {var r=b.match (x),t=r[2];while (a[t]){t=a[t]};a[r[1]]=t;return a}, {v:0})).reduce (function (a,b) {return (c[b]=="x"?1:0) + a},0)
        }
    };
    console.log (x.state);  //1
    console.log (x.state);  //1
    y = x;
    console.log (x.state);  //2
    z = y;
    console.log (x.state);  //3    
    a = z;
    b = a;
    console.log (x.state);  //5
    a = null;
    console.log (x.state);  //4
    b = null;
    console.log (x.state);  //3
})() //1 1 2 3 5 4 3 

function getLine(n) {
   try {
      to
   } catch (dat) {
      var stack = dat.stack.split('\n');
       for (var i = 0; i < stack.length; i++) {
           if (~stack[i].indexOf ('getLine')) break;          
       }
      return dat.stack.split ('\n')[i + ~~n].match (/:(\d+)/)[1] - ~~window.hasOwnProperty ('__commandLineAPI')
   }
}

C5H8NNaO4

Posted 2014-06-04T15:11:50.157

Reputation: 1 340

2Care to explain what your doing? – Ryan – 2014-06-06T16:30:44.417

5... what in the world is this? O_o – Doorknob – 2014-06-06T16:38:49.903

@Doorknob A getter that returns the result, of calling a function, which counts how often an identifiername is being referenced as rval, in an assignment expression, within a given sourcetext up to a given line, passing its enclosing functions source and the line the getter got called from as arguments. Everything else is a messy provisorical tokenizer. --- I don't know how else i should call it. In other words. In other words: The getter counts the number of assignments of references to x up to the line it got called from, the rest is a not finished tokenizer. – C5H8NNaO4 – 2014-06-06T16:57:18.510

But hey :D It matches the requirements – C5H8NNaO4 – 2014-06-06T16:58:30.770

Could you write an explanation in your answer, I feel too stupid trying to comprehend your answer :( – Braiam – 2014-06-06T16:58:47.817

@Braiam Nah, that's my fault. I'm rather.. not good at explaining stuff :/ Sure, I'll try to add a more comprehensible explanation to the Answer, later. I gotta go now – C5H8NNaO4 – 2014-06-06T17:01:29.553

Maybe i should golf it a bit – C5H8NNaO4 – 2014-06-06T17:02:39.393

This is longest code I have seen on this site ! – Nicolas Barbulesco – 2014-06-07T13:22:18.850

1The longest …and the widest ! – Nicolas Barbulesco – 2014-06-07T13:44:49.140

1@NicolasBarbulesco I made it shorter – C5H8NNaO4 – 2014-06-08T01:13:55.903

4

Python

It's cheating a little, but how about:

import gc
class A(object):
    @property
    def state(self):
        return len(gc.get_referrers(self))

a = A()
print a.state
b = {"x": a}
print a.state
a.y = a
print a.state
del a
print b["x"].state

James_pic

Posted 2014-06-04T15:11:50.157

Reputation: 3 988

4

C++11

though this can be extended for other languages that supports implicit / explicit destrucors

#include <iostream>
using namespace std;

class Foo {
    int *ptr;
public:
    Foo() {
        ptr = new int(0);
    }   
    int state() {
        return *ptr;
    }
    ~Foo() {
        (*ptr)++;
    }
};
int main() {
    Foo a, b;
    cout << a.state() << " " << b.state() << "\n";
    {
        Foo c, d;
        c = a;
        d = b;
    }
   cout << a.state() << " " << b.state()  << "\n";

   return 0;
}

The default assignment operator performs a shallow copy. So the receiving object still owns the pointer and any change implicitly affects the original object;

Abhijit

Posted 2014-06-04T15:11:50.157

Reputation: 2 841

1Yeah, a new without a single delete in the program. Although, for this task it's good enough I think :) – Ruslan – 2014-06-05T19:07:59.977

What are the outputs ? – Nicolas Barbulesco – 2014-06-07T13:14:37.960

1From what I understand (C++ is far away…), here the assignment does not change the state. Otherwise, move the cout line up before the } and tell whether that works. :-) – Nicolas Barbulesco – 2014-06-07T13:28:42.527

4

Scala

Implicit conversions let you accomplish this while assigning to a normal local variable:

import scala.language.implicitConversions

class Obj {
  var counter = 0
}

implicit def o2s(x: Obj): String = {
  x.counter += 1
  x.toString
}

val obj = new Obj
println(obj.counter)
val s: String = obj
println(obj.counter)

You can accomplish that with inferred types, too:

var s = ""
s = obj

You can also use a custom setter method, though that requires the L-value to be a field:

object L {
  var _value = new Obj
  def value = _value
  def value_=(x: Obj): Unit = {
    _value = x
    x.counter += 1
  }
}

val obj = new Obj
println(obj.counter)
L.value = obj
println(obj.counter)

Dan Getz

Posted 2014-06-04T15:11:50.157

Reputation: 533

3

D

struct Obj {
    int state;

    void opAssign (ref Obj other) {
        ++other.state;
    }
}

void main () {
    import std.stdio;

    Obj obj, lvalue;
    writeln(obj);
    lvalue = obj;
    writeln(obj);
}

Output:

Obj(0)
Obj(1)

Hugo Dubé

Posted 2014-06-04T15:11:50.157

Reputation: 91

3

C++

This behavior is actually specified in the standard (and that's why it was deprecated).

#include<iostream>
#include<memory>
int main()
{
    std::auto_ptr<int> a(new int(0));
    std::cout<<a.get()<<'\n';
    std::auto_ptr<int> b = a;
    std::cout<<a.get()<<'\n';
}

Output

some address
0

The process that causes this is the same as Abhijit's answer but without requiring a std::move and the same as marinus' answer but using a standard class instead of defining it myself.

Edit: I'm adding some explanation. In the output, "some address" will actually be a hex value for the address of the allocated integer. std::auto_ptr releases its stores pointer when assigned to another auto_ptr and sets its internal pointer to 0. Calling get() retrieves access to the stores pointer.

JKor

Posted 2014-06-04T15:11:50.157

Reputation: 176

I suspect that the "output" here is not the real output. – Nicolas Barbulesco – 2014-06-07T13:34:34.543

Can you explain what this is supposed to do ? Especially the method get() ? Why would it return 0 at the end ? – Nicolas Barbulesco – 2014-06-07T13:37:00.757

@Nicholas yep. This output is not the true output, but a more general output (I also didn't have access to a compiler so I didn't have an example of a valid address at the time). – JKor – 2014-06-07T19:36:26.910

1Hm, this fails to compile on gcc 4.8. – Michael Hampton – 2014-06-08T02:04:06.670

1I fixed the compilation errors. There are still warnings if you are compiling for c++11 because auto_ptr is deprecated. – JKor – 2014-06-08T06:05:19.543

3

In Java

I thought this was impossible in Java. But…

Main class :

public class MyAppOfCats {

  public static void main(String[] args) {
    Cat tom = new Cat();
    System.out.println(tom.state()); 
    // Output : NOT-BEST-CAT
    Cat.bestCat = tom;
    System.out.println(tom.state());
    // Output : BEST-CAT
  }

}

Class Cat :

public class Cat {

  static Cat bestCat;

  public Cat() {
    super();
  }

  public String state() {
      return ((this == Cat.bestCat) ? "BEST-CAT" : "NOT-BEST-CAT");
  }

}

I have been inspired by @tbodt.

Nicolas Barbulesco

Posted 2014-06-04T15:11:50.157

Reputation: 249

1I know it's not code-golf, but you realize you can just remove the constructor and it's still the same, right? – David Conrad – 2014-06-06T20:37:59.000

2This isn't "an object whose state changes on assignment". This is you manipulating a global value and then printing something based on it. It's no different from Cat.x = 2 and then printing Cat.x. – Chris Hayes – 2014-06-08T06:53:03.627

@Chris — The object state is based on a “global value”. So the object state changes on assignment. The question states ;-) that the state may be a deterministic, idempotent method. My method state() is such a method. – Nicolas Barbulesco – 2014-06-08T11:40:57.490

No, the object state changes on this particular assignment. If I did Cat otherCat = tom the state wouldn't have changed at all. I have a hard time believing this meets the letter or spirit of the rules. – Chris Hayes – 2014-06-08T16:08:02.873

@Chris — Of course the object changes on this assignment ! The question asks for an object whose state be changed by the assignment. Not for an object whose state be changed by any assignment. – Nicolas Barbulesco – 2014-06-08T16:24:08.153

3

Ruby

As promised, here's the answer that inspired the question.

obj = Class.new { def self.state; to_s[/</] ? "Has not been assigned\n" : "Assigned to #{to_s}"; end }

print obj.state

LValue = obj

print obj.state

Class.new creates an anonymous class. Calling to_s on an anonymous class gives the default string representation of objects, which looks like #<Class:0x007fe3b38ed958>. However, once the class has been assigned to a constant, to_s becomes that constant. In Ruby, a constant is a variable that begins with an uppercase letter, so obj is a reference to the class that allows it to stay anonymous.

My code wraps to_s in a state method, so the output becomes

Has not been assigned
Assigned to LValue

Unlike most of the solutions here, this only works once: assigning obj to another constant won't change its string representation, and neither will assigning a new value to LValue.

histocrat

Posted 2014-06-04T15:11:50.157

Reputation: 20 600

3

Python

import sys
class K:state = property(sys.getrefcount)

pppery

Posted 2014-06-04T15:11:50.157

Reputation: 3 987

2

Python 2.x

I couldn't find a proper way to do this without defining an extra class.

class State(object):
    def __init__(self):
        self.state = 0
    def __set__(self, obj, other):
        # Keep different references
        other.state += 1
        self.state += 2

class Program(object):
    obj, value = State(), State() # Create two State-objects
    def __init__(self):
        print "Before assignment:", self.obj.state, self.value.state # 0 0
        self.value = self.obj # Set value to obj (supposedly)
        print "After  assignment:", self.obj.state, self.value.state # 1 2
        self.value = self.obj
        print "2nd    assignment:", self.obj.state, self.value.state # 2 4

Program()

seequ

Posted 2014-06-04T15:11:50.157

Reputation: 1 714

2

Java

All the other solutions use their language's form of operator overloading. Java doesn't have operator overloading, so I thought I was stuck. But I came up with something.

Here's the main class:

public class Program {
    public static void main(String[] args) {
        Thing thing = new Thing(0);
        System.out.println(thing.getState());
        Thing.otherThing = thing;
        Thread.sleep(1);
        System.out.println(thing.getState());
    }
}

There are a few suspicious lines, but they wouldn't do anything if the Thing class was completely normal. It isn't:

public class Thing {
    private int state;

    public Thing(int state) {
        this.state = state;
    }

    public int getState() {
        return state;
    }

    // Please do your best to ignore the rest of this class.
    public static volatile Thing otherThing;
    static {
        Thread t = new Thread() {
            public void run() {
                Thing t = otherThing;
                while (true)
                    if (t != otherThing) {
                        t = otherThing;
                        t.state++;
                    }
            }
        };
        t.setDaemon(true);
        t.start();
    }
}

It's not guaranteed to work because of the threads, but I tested it on JDK 1.8u5, and it works there.

tbodt

Posted 2014-06-04T15:11:50.157

Reputation: 2 176

http://meta.codegolf.stackexchange.com/a/1657/11376 – Kyle Kanos – 2014-06-05T02:04:11.070

@KyleKanos Got rid of all unicode chars >U+00FF – tbodt – 2014-06-05T22:44:57.410

1

Common Lisp

I define state as the number of special variables bound to a vector. So, assignment to a special variable changes the state.

(defgeneric state (object)
  (:documentation "Get the state of this object."))

(defmethod state ((object vector))
  ;; The state of a vector is the number of symbols bound to it.
  (let ((count 0))
    ;; Iterate each SYM, return COUNT.
    (do-all-symbols (sym count)
      ;; When SYM is bound to this vector, increment COUNT.
      (when (and (boundp sym) (eq (symbol-value sym) object))
    (incf count)))))

(defparameter *a* #(this is a vector))
(defparameter *b* nil)
(defparameter *c* nil)

(print (state *a*))
(setf *b* *a*)
(print (state *a*))
(print (state *a*))
(setf *c* *a*)
(print (state *a*))

Output:

1 
2 
2 
3 

It only works with assignments to special variables, not to lexical variables, nor to slots within an object.

Beware that do-all-symbols looks in all packages, so it misses variables that have no package. It might double-count symbols that exist in more than one package (when one package imported the symbol from another package).

Ruby

Ruby is almost the same, but I define state as the number of constants referring to an array.

class Array
  # Get the state of this object.
  def state
    # The state of an array is the number of constants in modules
    # where the constants refer to this array.
    ObjectSpace.each_object(Module).inject(0) {|count, mod|
      count + mod.constants(false).count {|sym|
        begin
          mod.const_get(sym, false).equal?(self)
        rescue NameError
          false
        end
      }
    }
  end
end

A = %i[this is an array]
puts A.state
B = A
puts A.state
puts A.state
C = A
puts A.state

Output:

state-assign.rb:9:in `const_get': Use RbConfig instead of obsolete and deprecated Config.
1
2
2
3

This is a generalization of histocrat's answer to Ruby objects that are not classes or modules. The warning appears because the Config constant autoloads some code that made the warning.

kernigh

Posted 2014-06-04T15:11:50.157

Reputation: 2 615

0

C++

The result may differ in different platforms. Tested on ideone.

#include <iostream>
#include <cassert>
// File format: [ciiiiciiii...] a char (1 byte) followed by its state (4 bytes)
// Each group takes 5 bytes
char Buffer[30]; // 5*6, six groups

struct Group {
    char c;
    int state;
};

int main(void) {
    assert(sizeof(char) == 1);
    assert(sizeof(int) == 4);

    Group& first_group = *(Group*)(&Buffer[0]); // Group 1 is at 0
    Group& second_group = *(Group*)(&Buffer[5]); // Group 2 is at 5

    first_group.c = '2';
    first_group.state = 1234;

    std::cout << first_group.state << std::endl;

    second_group = first_group;

    std::cout << first_group.state << std::endl;

    return 0;
}

Output:

1234
13010

jingyu9575

Posted 2014-06-04T15:11:50.157

Reputation: 101

0

C#

class A
{
    public int N { get; set; }
    public override string ToString() { return N.ToString(); }
}
class B
{
    public int N { get; set; }
    public override string ToString() { return N.ToString(); }
    public static implicit operator A(B b) { b.N = -b.N; return new A { N = b.N }; }
}
public static void Test()
{
    A a = new A { N = 1 };
    B b = new B { N = 2 };
    Console.WriteLine("a is {0}, b is {1}", a, b);
    Console.WriteLine("a is {0}, b is {1}", a, b);
    a = b;
    Console.WriteLine("a is {0}, b is {1}", a, b);
    Console.WriteLine("a is {0}, b is {1}", a, b);
}

Output:

a is 1, b is 2
a is 1, b is 2
a is -2, b is -2
a is -2, b is -2

ClickRick

Posted 2014-06-04T15:11:50.157

Reputation: 245

What does this do ? Is this overloading the operator = ? – Nicolas Barbulesco – 2014-06-07T13:20:57.923

@Nicolas Not exactly. It's when casting from a B to an A, because the implicit operator A(B b) has side-effects. – ClickRick – 2014-06-08T22:22:57.947