割り当て時に状態が変化するオブジェクトを作成します


31

Rubyでこれが可能であることは非常に奇妙です(すぐに言いません)。

obj = #code redacted

print obj.state # Some value.

LValue = obj

print obj.state # Different value!

あなたの課題は、おおよそこの形式のコードを作成することです。オブジェクトを作成し、変数に割り当てます。stateオブジェクトを参照するために古い識別子(上記)を使用している場合でも、オブジェクトが新しい識別子(LValue上記)に割り当てられた後に変化する、上記のような定義済み属性(または決定論的、べき等法)が必要ですobj

強調のための編集stateまたは同等のものはdem等でなければならないため、値を変更するアクセサーを作成するか、他の理由で連続して複数回呼び出されたときに異なる結果を返すことは有効な解決策ではありません。または、もっと簡単に言うと、状態を変更するのは割り当てでなければなりません。

割り当てられた言語はすべて資格がありますが、おそらく完全に正当な解決策がない場合もあります。数日後に誰も回答しない場合は、Rubyの回答を投稿し、最高の投票による回答をローリングベースで受け入れます。


実際に変更するには、LValue = obj行が必要stateですか?(取得するたびに増分するプロパティをC#で作成することもできます)
Tim S. 14年

2
はい、それはメソッドがべき等である必要があると言って私が意図したものです。それをより明確にするために編集します。
histocrat

はい、ありがとう。私はその部分に目を通したに違いない。
ティムS. 14年

4
オブジェクトの参照カウントを返すだけで機能しますか?
ニックT 14年

オブジェクト自体に破壊的な変更を加えますか?EmacsLisp:(setq a (list "val")) (setq b (nconc a "val2"))たとえば。 その時点でa評価を終了し("val" . "val2")ます。
ジョナサンリーチペピン

回答:


30

C ++

適切なツールを使用すれば、これは簡単です。

#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;
}

出力:

3 4
4 5 2 3

12
タイトルを見た瞬間、誰かがオペレーターのオーバーロードを行うことを知っていました。それは明らかな方法です。賛成票を持っている。

17

PHP(デバッグビルド、> = 5.4)

getterでオブジェクトのrefcountを使用します。(したがって、割り当てによって、refcountが増加し、値が変更されます)

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);

14

C#

2つの簡単なオプション:

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();
}

または、同じメモリに単純に書き込むこともできます。

[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(); }
}

12

TeX、ここの他の回答よりもはるかに短い

\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.

タイプセットシステムとして、TeXにはタイプセット素材を含む「ボックス」タイプがあります。最も一般的な使用例は、コピーを作成するのではなく、このマテリアルを移動したり分割したりすることであるため、ボックスは通常使用時に削除されますメモリ内の実際のボックスへ)。魔法は必要ありません。


8

C ++ 11(だから皆さんは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;
}

7

Fortran 03

これは、HugoのDの回答に多少似ていますが、もう少し隠されています(#$%^が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

出力は

this%state = 1
this%state = 0

何が起こったのかを把握できれば、ボーナスポイントがあなたに与えられます!そうでない場合:

setNewフォームcall b%setNew(a)でプロシージャを呼び出す場合、b暗黙的に最初の引数であり、2番目の引数ではありません。


7

パワーシェル

これにより、stateプロパティがオブジェクトを指す変数の名前であるオブジェクトが作成されます。

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

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

出力

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

注:割り当てが子スコープで発生する場合、これは機能しません。

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

出力

Before: a,this
After: a,this

Get-Variableはスマートです!
mazzy

5

Perl 5

Perlでそれを行う1つの方法を次に示します。

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};

この出力:

1
2

説明:

これはオーバーロードの簡単なアプリケーションです。具体的には、文字列変換演算子をオーバーロードします""。これは、オーバーロードされたオブジェクトが割り当てられたときに呼び出されますsubstr()(はい、Perlで有効な左辺値です)。

Perlには、割り当てられたものをすべて文字列化する特別な変数がたくさんあります。たとえば、次も機能します。

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

代替ソリューション

別の方法を次に示します。

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;

ここに、state文字通りオブジェクトへの参照の数を数えるメソッド(さらにタイ/オーバーロードシェナンガンを持つ属性にできますが、それは事態を複雑にします)です。したがって、最初のソリューションとは異なり、実際に$objオブジェクト参照を保持できる通常の変数に割り当てて、状態を変更する必要があります。


5

JavaScript

それでは、SSCCEとして機能する短いバージョンを作成しましたが、JavaScriptを適切に解析しようとはしなかったため、より複雑なスクリプト内に配置すると参照カウントが機能しない可能性があります。

(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')
   }
}

2
何をしているのか説明してくれませんか?
ライアン14

5
...これは何ですか?O_o
ドアノブ

@Doorknob関数を呼び出した結果を返すゲッター。識別子式がrvalとして参照されている頻度を、割り当て式で、指定されたソーステキスト内で指定された行まで、その囲む関数ソースと行を渡しますgetterが引数として呼び出されました。他のすべては厄介な暫定的なトークナイザーです。--- 他にどのように呼べばいいのかわかりません。言い換えると。言い換えれば、ゲッターはxへの参照の割り当て数を、呼び出し元の行までカウントし、残りは未完成のトークナイザーです。
C5H8NNaO4 14

1
最長…そして最長!
ニコラスバルブレスコ14年

1
@NicolasBarbulesco私はそれを短く
C5H8NNaO4

4

Python

少しごまかしていますが、どうですか:

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

4

C ++ 11

ただし、これは暗黙的/明示的なデストゥルーをサポートする他の言語に拡張できます

#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;
}

デフォルトの代入演算子は、浅いコピーを実行します。したがって、受信オブジェクトは引き続きポインターを所有し、変更は暗黙的に元のオブジェクトに影響します。


1
ええ、プログラムにnewシングルdeleteはありません。ただし、このタスクでは十分だと思います:)
ルスラン14年

出力は何ですか?
ニコラスバルブレスコ

1
私が理解していることから(C ++は遠く離れています...)、ここでは割り当ては状態を変更しません。それ以外の場合は、cout行を前に移動して、それ}が機能するかどうかを確認します。:
ニコラスバルブレスコ14年

4

スカラ

暗黙的な変換により、通常のローカル変数に割り当てながらこれを実現できます。

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)

推論型でもこれを実現できます。

var s = ""
s = obj

カスタムのセッターメソッドを使用することもできますが、これにはL値がフィールドである必要があります。

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)

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);
}

出力:

Obj(0)
Obj(1)

3

ルビー

約束されたように、ここに質問を引き起こした答えがあります。

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匿名クラスを作成します。to_s匿名クラスを呼び出すと、オブジェクトのデフォルトの文字列表現が得られます#<Class:0x007fe3b38ed958>。ただし、クラスが定数に割り当てられると、その定数にto_sなります。Rubyでは、定数は大文字で始まる変数であるためobj、匿名を維持できるクラスへの参照です。

私のコードto_sstateメソッドでラップしているため、出力は

Has not been assigned
Assigned to LValue

ここでのほとんどのソリューションとは異なり、これは1回だけ機能します。obj別の定数に割り当てても文字列表現は変更されず、新しい値もに割り当てられませんLValue


3

Javaで

これはJavaでは不可能だと思いました。しかし…

メインクラス:

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
  }

}

クラス猫:

public class Cat {

  static Cat bestCat;

  public Cat() {
    super();
  }

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

}

@tbodtに触発されました。


1
私はそれがコードゴルフではないことを知っていますが、あなたはコンストラクタを削除するだけでいいことを知っています、それでも同じですよね?
デビッドコンラッド14

2
これは「割り当て時に状態が変化するオブジェクト」ではありません。これは、グローバル値を操作し、それに基づいて何かを印刷することです。それCat.x = 2は印刷と違いはありませんCat.x
クリスヘイズ14年

@Chris — オブジェクトの状態は「グローバル値」に基づいています。そのため、割り当て時にオブジェクトの状態が変わります。質問 ;-) 状態が決定論的でべき等の方法であるかもしれないと述べています。私のメソッドstate()はそのようなメソッドです。
ニコラスバルブレスコ14年

いいえ、この特定の割り当てでオブジェクトの状態が変わります。私がやっCat otherCat = tomた場合、状態はまったく変わっていなかっただろう。これがルールの文字や精神を満たしているとは信じられません。
クリスヘイズ14年

@Chris —もちろん、この割り当てでオブジェクトが変更されます!質問は、割り当てによって状態が変更されるオブジェクトを要求します。割り当てによって状態が変更されるオブジェクトではありません。
ニコラスバルブレスコ14年

3

C ++

この動作は実際に標準で指定されています(そして、それが非推奨になった理由です)。

#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';
}

出力

some address
0

これを引き起こすプロセスは、Abhijitの答えと同じですが、aを必要std::moveとせず、Marinusの答えと同じですが、自分で定義する代わりに標準クラスを使用します。

編集:説明を追加します。出力では、「一部のアドレス」は実際には、割り当てられた整数のアドレスの16進値になります。 std::auto_ptr別に割り当てられたときにストアポインターを解放し、auto_ptrその内部ポインターを0に設定しget()ます。呼び出しはストアポインターへのアクセスを取得します。


ここでの「出力」は実際の出力ではないと思います。
ニコラスバルブレスコ14年

これが何をするのか説明できますか?特にメソッドget()?最後に0を返すのはなぜですか?
ニコラスバルブレスコ14年

@Nicholasうん。この出力は実際の出力ではなく、より一般的な出力です(コンパイラーにもアクセスできなかったため、その時点で有効なアドレスの例はありませんでした)。
JKor

1
うーん、これはgcc 4.8でのコンパイルに失敗します。
マイケルハンプトン14年

1
コンパイルエラーを修正しました。auto_ptr推奨されていないため、c ++ 11用にコンパイルしている場合は、まだ警告があります。
JKor 14年


2

Python 2.x

追加のクラスを定義せずにこれを行う適切な方法を見つけることができませんでした。

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()

2

Java

他のすべてのソリューションでは、言語の形式の演算子オーバーロードが使用されます。Javaには演算子のオーバーロードがないため、立ち往生していると思いました。しかし、私は何かを思いつきました。

メインクラスは次のとおりです。

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());
    }
}

疑わしい行がいくつかありますが、Thingクラスが完全に正常である場合は何もしません。そうではありません:

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();
    }
}

スレッドのために動作することは保証されていませんが、JDK 1.8u5でテストし、そこで動作します。



@KyleKanosすべてのユニコード文字を
削除

1

Common Lisp

状態は、ベクトルにバインドされた特殊変数の数として定義します。そのため、特殊変数への割り当てにより状態が変更されます。

(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*))

出力:

1 
2 
2 
3 

これは、字句変数やオブジェクト内のスロットへの割り当てではなく、特殊変数への割り当てでのみ機能します。

do-all-symbolsすべてのパッケージを調べることに注意してください。したがって、パッケージを持たない変数を見逃します。複数のパッケージに存在するシンボルをダブルカウントする場合があります(あるパッケージが別のパッケージからシンボルをインポートした場合)。

ルビー

Rubyはほぼ同じですが、配列を参照する定数の数として状態を定義します。

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

出力:

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

これは、クラスまたはモジュールではないRubyオブジェクトに対するhistorcratの答えの一般化です。警告が表示されるのは、Config定数が警告を行ったコードを自動ロードするためです。


0

C ++

プラットフォームによって結果が異なる場合があります。イデオンでテスト済み。

#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;
}

出力:

1234
13010

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);
}

出力:

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

これは何をしますか?これは演算子をオーバーロードしています=か?
ニコラスバルブレスコ14年

@Nicolas正確ではありません。キャストするとき、それはだBAため、implicit operator A(B b)副作用があります。
ClickRick 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.