Raku에서 프라이빗 및 퍼블릭 속성 및 접근 자 혼합


12
#Private attribute example
class C { 
    has $!w;                            #private attribute
    multi method w { $!w }              #getter method
    multi method w ( $_ ) {                 #setter method
        warn “Don’t go changing my w!”;   #some side action
        $!w = $_
    }  
}
my $c = C.new
$c.w( 42 )
say $c.w #prints 42
$c.w: 43
say $c.w #prints 43

#but not
$c.w = 44
Cannot modify an immutable Int (43)

지금까지는 합리적이며

#Public attribute example
class C { 
    has $.v is rw    #public attribute with automatic accessors
}
my $c = C.new
$c.v = 42
say $c.v #prints 42

#but not
$c.v( 43 ) #or $c.v: 43
Too many positionals passed; expected 1 argument but got 2

나는 '='할당의 즉각적인 것을 좋아하지만 다중 방법이 제공하는 부수적 인 행동으로 번지가 쉬워야합니다. 나는 이것이 서로 다른 두 세계이며 혼합되어 있지 않다는 것을 이해합니다.

그러나 나는 왜 그냥 갈 수 없는지 이해하지 못한다 $ cv (43) public 속성을 설정하려면

  1. raku는이 두 가지 모드를 혼합하지 말라고 지시합니다. 일부 속성은 개인 속성과 일부 속성은 압력이 방법 방법에 대한 압력입니다 (일부 : 결장의 설탕)-이것이 Raku 디자인의 의도입니까?
  2. 뭔가 빠졌습니까?

프록시를 사용할 수 있습니다
user0721090601

프록시를 어떻게 사용할 수 있습니까? 내 말은 접근자가 이미 is rw지정 되면 컨테이너를 이미 반환한다는 의미 입니다. 프록시를 반환해도 접근 자의 허용 가능한 매개 변수 수는 변경되지 않습니다.
Elizabeth Mattijsen

@ElizabethMattijsen 아마도 질문을 오해했을 것입니다. 그러나 이것은 그가 원하는 (두 가지 모두 가능하게 = foo하고 .(foo)설정하기 위해) 작동하고 부작용이 두 경우 모두에서 수행되도록하는 것 같습니다 (가져올 때만는
user0721090601

답변:


13

이것이 Raku 디자인의 의도입니까?

Raku 가이 분야에서 완전히 분류되지 않은 것은 아닙니다. 귀하의 질문은 Raku 디자인의 두 가지 주제에 대해 다루며, 둘 다 약간의 토론 가치가 있습니다.

라쿠는 일류 l- 값을 가지고 있습니다

라쿠는 일류가되는 l- 값을 충분히 활용합니다. 우리가 쓸 때 :

has $.x is rw;

생성되는 방법은 다음과 같습니다.

method x() is rw { $!x }

is rw여기에는 메소드가 반환을 나타냅니다 리터 값 이다,에 할당 할 수있는 뭔가를 -. 따라서 우리가 쓸 때 :

$obj.x = 42;

이것은 구문 설탕이 아닙니다. 실제로 메소드 호출이며 할당 연산자가 그 결과에 적용됩니다. 메서드 호출은 Scalar속성 의 컨테이너를 반환하고 할당 할 수 있기 때문에 문제가되지 않습니다 . 바인딩을 사용하여 이것을 두 단계로 나누면 사소한 구문 변환이 아닌 것을 알 수 있습니다. 예를 들면 다음과 같습니다.

my $target := $obj.x;
$target = 42;

객체 속성에 할당됩니다. 이 같은 메커니즘은 목록 할당을 포함하여 수많은 다른 기능 뒤에 있습니다. 예를 들면 다음과 같습니다.

($x, $y) = "foo", "bar";

List컨테이너를 포함하는 컨테이너 를 구성하여 작동 $x하며 $y,이 경우 대입 연산자는 각면을 쌍으로 반복하여 대입을 수행합니다. 이것은 우리가 rw그곳에서 객체 접근자를 사용할 수 있다는 것을 의미 합니다 :

($obj.x, $obj.y) = "foo", "bar";

그리고 그것은 모두 자연스럽게 작동합니다. 이것은 또한 배열과 해시 조각에 할당하는 메커니즘입니다.

또한 Proxy읽기 및 쓰기 동작이 사용자의 통제하에있는 l- 값 컨테이너를 만들기 위해 사용할 수 있습니다 . 따라서 부작용을에 넣을 수 STORE있습니다. 하나...

Raku는 "세터"보다 의미 론적 방법을 권장합니다

OO를 설명 할 때 "캡슐화"및 "데이터 숨기기"와 같은 용어가 종종 나타납니다. 여기서 핵심 아이디어는 객체 내부의 상태 모델, 즉 동작 (메서드)을 구현하기 위해 필요한 데이터를 표시하도록 선택하는 방식과 같이 새로운 요구 사항을 처리하기 위해 자유롭게 진화 할 수 있다는 것입니다. 물체가 복잡할수록 더욱 자유 로워집니다.

그러나 게터와 세터는 상태와 암시 적으로 연결된 메서드입니다. 상태에 직접 액세스하지 않고 메소드를 호출하기 때문에 데이터 숨기기를 달성한다고 주장 할 수 있지만 내 경험은 외부 코드가 일련의 setter 호출을 수행하여 작업을 수행하는 위치에서 빠르게 끝나는 것입니다. 기능 부러워 안티 패턴의 형태. 그리고 우리가 그렇게 한다면 , getter와 setter 연산을 혼합하여 연산을 수행하는 객체 외부의 논리로 끝날 것입니다. 실제로 이러한 작업은 수행중인 작업을 설명하는 이름을 가진 방법으로 노출되어야합니다. 우리가 동시 설정에 있다면 더욱 중요합니다. 잘 설계된 객체는 종종 메소드 경계에서 보호하기가 상당히 쉽습니다.

즉, 많은 용도 class는 실제로 레코드 / 제품 유형입니다. 단순히 여러 데이터 항목을 그룹화하기 위해 존재합니다. .시길이 접근자를 생성 할뿐만 아니라 다음과 같은 경우도 우연 이 아닙니다.

  • 속성을 기본 객체 초기화 로직 (즉, class Point { has $.x; has $.y; }로 인스턴스화 할 수 있음 Point.new(x => 1, y => 2))에 의해 설정되도록 선택하고 .raku덤프 메소드 에서 속성을 렌더링합니다 .
  • 속성을 기본 .Capture객체로 선택합니다. 즉,이를 파괴 (예 :)에서 사용할 수 있습니다 sub translated(Point (:$x, :$y)) { ... }.

보다 절차 적이거나 기능적인 스타일로 작성 class하고 레코드 유형을 정의하는 수단으로 사용하려는 경우 원하는 것 입니다.

Raku 디자인은 세터에서 영리한 작업을 수행하는 데 최적화되어 있지 않습니다. 최적화하기 어려운 것으로 간주되기 때문입니다. 레코드 유형에 필요한 것 이상입니다. 일부 언어에서는 할당 된 내용에 대한 유효성 검사를 원한다고 주장 할 수 있지만 Raku subset에서는 해당 유형으로 전환 할 수 있습니다 . 동시에 우리가 실제로 OO 디자인을하고 있다면, getter / setter와 관련하여 생각하지 않고 상태 모델을 숨기는 의미있는 행동의 API가 필요합니다. 어쨌든 OO를 수행하는 데있어 중요한 부분 인 데이터와 행동.


Proxys 를주의하는 것이 좋습니다 (나는 그것을 제안했지만). 내가 그들을 매우 유용하게 찾은 유일한 시간은 내 것 LanguageTag입니다. 내부적으로는 (내부적으로 저장된) $tag.region유형의 객체를 반환 Region하지만 실제로는 사람들이 더 이상 말 $tag.region = "JP"을 하는 것이 훨씬 편리합니다 $tag.region.code = "JP". Str예를 들어, has Region(Str) $.region is rw(두 가지 별도의 계획이지만 우선 순위가 낮은 기능을 필요로하는) 유형에서 강제를 표현할 수있을 때까지는 실제로 일시적입니다.
user0721090601

디자인 근거를 설명하는 데 시간을내어 주셔서 감사합니다 @Jonathan-나는 기름과 물의 측면을 의심했고 나와 같은 비 CS 이사회에 대해 숨겨진 상태의 적절한 OO와 클래스 es의 응용 프로그램을 실제로 구별합니다. C ++로 박사 학위를받을 수있는 난해한 데이터 홀더를 구축하는 더 친숙한 방법. 그리고 프록시에 대한 당신의 생각을 위해 user072에게. 나는 이전에 Proxy에 대해 알고 있었지만 그것들 (및 / 또는 특성)이 기름과 물의 혼합을 막기 위해 의도적으로 상당히 성가신 구문이라고 의심했다.
p6steve

p6steve : Raku는 가장 일반적이고 쉬운 것을 매우 쉽게 만들도록 설계되었습니다. 일반적인 모델에서 벗어날 때 항상 가능합니다 (지금까지 원하는 것을 수행하는 세 가지 방법에 대해 보았지만 분명히 더 많이 있습니다).하지만 조금만 일하면 충분합니다. 당신이하고있는 일은 정말로 당신이 원하는 것입니다 그러나 특성, 프록시, 속어 등을 통해 필요할 때 멋진 물건을 실제로 활성화하기 위해 몇 가지 추가 문자 만 필요합니다.
user0721090601

7

그러나 나는 왜 그냥 갈 수 없는지 이해하지 못한다 $ cv (43) public 속성을 설정하려면

글쎄, 그것은 건축가에게 달려 있습니다. 그러나 진지하게, 그것은 단순히 Raku가 작동하는 표준 방식이 아닙니다.

이제, 만들 전적으로 가능할 것이다 Attribute모듈 공간, 같은의 특성 is settable다른 접근 방법을 만드는 것, 값을 설정하는 하나의 값을 수락합니다. 코어 에서이 작업을 수행 할 때의 문제는 세계에 기본적으로 그러한 뮤 테이터의 반환 값에 대해 2 개의 캠프가 있다고 생각한다는 것입니다. 새로운 값 또는 이전 값을 반환 합니까?

모듈 공간에서 이러한 특성을 구현하려면 저에게 연락하십시오.


1
감사합니다 @ 엘리자베스-이것은 흥미로운 각도입니다-나는 여기 에이 질문을 치고 있으며 트릭 (또는 내 기술)을 수행 할 특성을 구축하는 데 충분한 투자금이 없습니다. 나는 최선의 코딩 관행에 대해 머리를 숙이고 그것을 맞추려고 노력했다. 그리고 Raku의 디자인이 모범 관행에 맞춰지기를 바랐다.
p6steve

6

나는 현재 당신이 혼란스러워 한 것 같습니다. 1 그 문제를 다루기 전에 혼란스럽지 않은 부분부터 다시 시작하겠습니다.

나는 =과제 의 즉시 성을 좋아 하지만 여러 방법이 제공하는 부수적 인 행동으로 번지가 쉬워야합니다. 난 그냥 갈 수없는 이유 ... 이해가 안 $c.v( 43 )공용 속성을 설정하려면

이 모든 것을 있습니다 . 즉 =, 다음과 같은 경우 할당과 다중 방법을 사용하고 동시에 "그냥 가십시오 $c.v( 43 )"라고 말합니다.

class C {
  has $!v;
  multi method v                is rw {                  $!v }
  multi method v ( :$trace! )   is rw { say 'trace';     $!v }
  multi method v ( $new-value )       { say 'new-value'; $!v = $new-value }
}
my $c = C.new;
$c.v = 41;
say $c.v;            # 41
$c.v(:trace) = 42;   # trace
say $c.v;            # 42
$c.v(43);            # new-value
say $c.v;            # 43

혼란의 가능한 소스 1

배후에서 다음 has $.foo is rw과 같은 행을 따라 속성과 단일 메소드를 생성합니다.

has $!foo;
method foo () is rw { $!foo }

위의 내용은 정확하지 않습니다. 우리가보고있는 행동을 고려할 때, 컴파일러의 자동 생성 된 foo메소드는 어떻게 든 같은 이름의 새로운 메소드가 자동으로 섀도 잉 하는 방식으로 선언되고 있습니다. 2

따라서 속성과 이름이 같은 하나 이상의 사용자 정의 메소드 를 원할 경우, 일반적으로 담당하는 동작을 유지하려면 자동으로 생성 된 메소드를 수동으로 복제 해야합니다 .

각주

1 비공개 vs 공개 게터 / 세터에 대한 Raku의 의견과 공개 게터 / 세터를 선언 할 때 뒤에서하는 일 (즉, write has $.foo) 에 대한 명확하고 철저하고 권위있는 설명은 jnthn의 답변을 참조하십시오 .

2 속성에 대해 자동 생성 된 접근 자 메서드가 선언 된 only경우 Raku는 동일한 이름의 메서드가 선언 된 경우 예외를 throw한다고 가정합니다. 선언 된 multi경우, 새 메소드도 선언 된 경우에는 그림자로 표시하지 않아야하며 multi그렇지 않은 경우 예외를 발생시켜야합니다. 따라서 자동 생성 접근자는 자동 섀도 잉을 허용하는 방식 으로 선언되지 only않고 multi대신 선언됩니다 .


Aha-감사합니다 @raiph-그것이 내가 놓쳤다 고 느꼈습니다. 이제 말이됩니다. Jnthn 당 아마 더 나은 OO 코더가되고 순수한 데이터 컨테이너에 대한 세터 스타일을 유지하려고 노력할 것입니다. 그러나 이것이 도구 상자에 있다는 것을 아는 것이 좋습니다!
p6steve
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.