31
\$\begingroup\$

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.

\$\endgroup\$
6
  • \$\begingroup\$ 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) \$\endgroup\$
    – Tim S.
    Commented Jun 4, 2014 at 20:27
  • 2
    \$\begingroup\$ Yes, that's what I intended by saying the method needed to be idempotent. I'll edit to make that clearer. \$\endgroup\$
    – histocrat
    Commented Jun 4, 2014 at 20:33
  • \$\begingroup\$ Ok, thanks. I must've glossed over that part. \$\endgroup\$
    – Tim S.
    Commented Jun 4, 2014 at 20:36
  • 4
    \$\begingroup\$ Would simply returning the refcount of the object work? \$\endgroup\$
    – Nick T
    Commented Jun 5, 2014 at 22:51
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Nov 4, 2015 at 22:38

22 Answers 22

29
\$\begingroup\$

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
\$\endgroup\$
1
  • 12
    \$\begingroup\$ The moment I saw the title, I knew someone would do operator overloading. It's the obvious way. Have an upvote. \$\endgroup\$
    – user16402
    Commented Jun 4, 2014 at 16:09
17
\$\begingroup\$

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);
\$\endgroup\$
14
\$\begingroup\$

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(); }
}
\$\endgroup\$
12
\$\begingroup\$

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.

\$\endgroup\$
8
\$\begingroup\$

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;
}
\$\endgroup\$
7
\$\begingroup\$

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.

\$\endgroup\$
7
\$\begingroup\$

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
\$\endgroup\$
1
  • \$\begingroup\$ Get-Variable is smart! \$\endgroup\$
    – mazzy
    Commented Dec 19, 2018 at 10:04
5
\$\begingroup\$

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.

\$\endgroup\$
5
\$\begingroup\$

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')
   }
}
\$\endgroup\$
10
  • 2
    \$\begingroup\$ Care to explain what your doing? \$\endgroup\$
    – Ryan
    Commented Jun 6, 2014 at 16:30
  • 5
    \$\begingroup\$ ... what in the world is this? O_o \$\endgroup\$
    – Doorknob
    Commented Jun 6, 2014 at 16:38
  • \$\begingroup\$ @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. \$\endgroup\$
    – C5H8NNaO4
    Commented Jun 6, 2014 at 16:57
  • 1
    \$\begingroup\$ The longest …and the widest ! \$\endgroup\$ Commented Jun 7, 2014 at 13:44
  • 1
    \$\begingroup\$ @NicolasBarbulesco I made it shorter \$\endgroup\$
    – C5H8NNaO4
    Commented Jun 8, 2014 at 1:13
4
\$\begingroup\$

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
\$\endgroup\$
4
\$\begingroup\$

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;

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Yeah, a new without a single delete in the program. Although, for this task it's good enough I think :) \$\endgroup\$
    – Ruslan
    Commented Jun 5, 2014 at 19:07
  • \$\begingroup\$ What are the outputs ? \$\endgroup\$ Commented Jun 7, 2014 at 13:14
  • 1
    \$\begingroup\$ From 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. :-) \$\endgroup\$ Commented Jun 7, 2014 at 13:28
4
\$\begingroup\$

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)
\$\endgroup\$
3
\$\begingroup\$

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)
\$\endgroup\$
0
3
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

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.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ I know it's not code-golf, but you realize you can just remove the constructor and it's still the same, right? \$\endgroup\$ Commented Jun 6, 2014 at 20:37
  • 2
    \$\begingroup\$ This 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. \$\endgroup\$ Commented Jun 8, 2014 at 6:53
  • \$\begingroup\$ @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. \$\endgroup\$ Commented Jun 8, 2014 at 11:40
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Jun 8, 2014 at 16:08
  • \$\begingroup\$ @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. \$\endgroup\$ Commented Jun 8, 2014 at 16:24
3
\$\begingroup\$

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.

\$\endgroup\$
5
  • \$\begingroup\$ I suspect that the "output" here is not the real output. \$\endgroup\$ Commented Jun 7, 2014 at 13:34
  • \$\begingroup\$ Can you explain what this is supposed to do ? Especially the method get() ? Why would it return 0 at the end ? \$\endgroup\$ Commented Jun 7, 2014 at 13:37
  • \$\begingroup\$ @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). \$\endgroup\$
    – JKor
    Commented Jun 7, 2014 at 19:36
  • 1
    \$\begingroup\$ Hm, this fails to compile on gcc 4.8. \$\endgroup\$ Commented Jun 8, 2014 at 2:04
  • 1
    \$\begingroup\$ I fixed the compilation errors. There are still warnings if you are compiling for c++11 because auto_ptr is deprecated. \$\endgroup\$
    – JKor
    Commented Jun 8, 2014 at 6:05
3
\$\begingroup\$

Python

import sys
class K:state = property(sys.getrefcount)
\$\endgroup\$
2
\$\begingroup\$

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()
\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
2
1
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
2
  • \$\begingroup\$ What does this do ? Is this overloading the operator = ? \$\endgroup\$ Commented Jun 7, 2014 at 13:20
  • \$\begingroup\$ @Nicolas Not exactly. It's when casting from a B to an A, because the implicit operator A(B b) has side-effects. \$\endgroup\$
    – ClickRick
    Commented Jun 8, 2014 at 22:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.