🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.ruby
Article #224

Re: Jak dodać własną metodę typu nazwa! do klasy?

#224
From: Marcin Mielżyński
Date: Sun, 08 Oct 2006 18:20
161 lines
5435 bytes
Rafał Komorowski wrote:

> 
>> b = a = 1.3
>> p a.round01!
>> p b
>>
>> i tego właśnie Matz chciał pewnie uniknąć...
> 
> Co masz na myśli? Zmianę prostej wartości "w miejscu"? Z tego co widzę, 
> funkcje z wykrzyknikiem są rzeczywiście zdefiniowane raczej do bardziej 
> skomplikowanych struktur, ja się nie upieram, żeby w Rubiego koniecznie 
> była wbudowana wersja "!", ale sama potrzeba istnienia zaokrąglania do 
> określonej cyfry po przecinku jest - i nie ma co z tym dyskutować. Jak 
> nie będzie tego w języku, to będzie trzeba to robić w kodzie Ruby, co 
> będzie bardziej kosztowne.

Chodzi o spójność z zachowaniem innych prostych typów jak np Fixnum, tak 
czy siak, Float jest zrobiony immutable zupełnie sztucznie - powód j.w. ;)
Jeśli będzie mutable i zrobisz round! - nagle zmieni się wartość jakiejś 
zmiennej w zupełnie innym miejscu programu - i szukaj wiartu w polu...

> Patrzę jeszcze raz na zacytowany powyżej kod i nie jestem pewien czy się 
> zrozumieliśmy, moja funkcja ma robić takie coś:
> 
> 3.1415.round01    => 3.1
> 3.1615.round01    => 3.2
> 

Opps.. było późno... Tu jest kod który to robi plus funkcja roundx która
jest sparametryzowana oraz ma wartość domyślną 10.0:


#include "ruby.h"

static VALUE
round01(num)
     VALUE num;
{
    double val = RFLOAT(num)->value;

    val = round(val * 10.0) / 10.0;

    RFLOAT(num)->value = val;

     return num;
}

static VALUE
roundx(argc, argv, a)
     // zmienna liczba argumentów
     int argc;
     VALUE *argv;
     // i nasz self
     VALUE a;
{
     // tutaj rozpakujemy pierwszy argument
     VALUE b;

     double rnd;

     rb_scan_args(argc, argv, "01", &b);

     // niekonieczne... ale dobry przykład sprawdzania typu argumentu
     // ten test to w zasadzie: long(b) & 1
	if (!FIXNUM_P(b)) {
	    rb_raise(rb_eArgError, "arg must be a Fixnum");
	}

     // jeśli nie ma argumentów
     if (argc == 0) {
         // wartość domyślna
         rnd = 10.0;
     // można też sprawdzić na argument 1 i wywalić błąd gdy != 1
     }else {
         rnd = NUM2INT(b);
     }

     double val = RFLOAT(a)->value;

     val = round(val * rnd) / rnd;

     RFLOAT(a)->value = val;

     return a;
}

void Init_Mutfloat(){
     rb_define_method(rb_cFloat, "round01!",  round01, 0);
     rb_define_method(rb_cFloat, "round!",  roundx, -1);
}


> 
>> Druga sprawa - patrzę na źródła 1.9 - RFloat jeszcze tam jest - ale 
>> może się zdarzyć że pewnego dnia FLoat stanie się immediate i nie 
>> będzie już żadnych sztuczek (np: rezerwacja 3 bitu z VALUE). W tej 
>> chwili Floaty w Rubym są bardzo kosztowne niewiele dając w zamian.
> 
> Nie rozumiem. Uważasz, że float powinien zniknąć jako struktura danych? 
> Czy chodzi ci tylko o ryzyko rozszerzania klasy Float wstawkami w C?
> 

Nie. Float powinien być immediate value, tylko że na razie brakuje 
bitów, już i tak Fixnum ma tylko 30 bitów:

(2**29).class -> Fixnum
(2**30).class -> Bignum

jeden bit stracony na flagę Fixnum, drugi bit stracony na mark&sweep
wstępnie polecam:
http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29


W architekturach 64 bitowych nie jest to tak bolesne...

Każda immediate value ma tylko _jedną_ wersję w całym interpreterze co 
oznacza że jest tylko jedna false, true, nil, 1, 2, 3, itd. Jeżeli 
odwołujesz się do instancji 1 - zawsze odwołujesz się do tej samej 
instancji niezależnie od miejsca programu!

p 1.object_id
p 1.object_id
p 1.object_id

p 1.1.object_id
p 1.1.object_id
p 1.1.object_id

daje:

3
3
3
21103790
21103710
21103630

Tak więc, immediate values wogóle nie rządzą się prawami rządzącymi 
referencjami - kopiowana jest tak na prawdę sama zmienna a nie wartość. 
Gdybyśmy zmienili wartość 1 na 4 - nagle wszystkie 1-dynki w skali 
całego interpretera stałyby się 4-kami!.

Podobne rozwiązanie panuje w javie gdzie np: dla java.lang.Integer 
wartości od -127 do 128 są w puli - zawsze będą miały takie same 
referencje, to samo dla false, true, i całego byte'a, chara w zakresie 
00..7F.
Tylko to grozi taki niebezpieczestwem:

Integer i=100;
Integer i2=100;

i==i2 -> true

Integer i=256;
Integer i2=256;

i==i2 już niekoniecznie!


lopex
Technical Details
Message-ID: <egbfi8$lou$1@news.onet.pl>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!news.onet.pl!not-for-mail
References: <eg90si$dj4$1@news.task.gda.pl> <eg96pc$u4t$1@news.onet.pl> <eg9d1o$q20$1@news.task.gda.pl> <eg9f9k$d1j$1@news.onet.pl> <egas2q$1rr$1@news.task.gda.pl>

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!news.onet.pl!not-for-mail
From: Marcin Mielżyński <lopx@gazeta.pl>
Newsgroups: pl.comp.lang.ruby
Subject: Re: Jak dodać własną metodę typu
 nazwa! do klasy?
Date: Sun, 08 Oct 2006 20:20:55 +0200
Organization: Onet.pl
Lines: 166
Message-ID: <egbfi8$lou$1@news.onet.pl>
References: <eg90si$dj4$1@news.task.gda.pl> <eg96pc$u4t$1@news.onet.pl> <eg9d1o$q20$1@news.task.gda.pl> <eg9f9k$d1j$1@news.onet.pl> <egas2q$1rr$1@news.task.gda.pl>
NNTP-Posting-Host: chello087207016023.chello.pl
Mime-Version: 1.0
X-Trace: news.onet.pl 1160331657 22302 87.207.16.23 (8 Oct 2006 18:20:57 GMT)
X-Complaints-To: usenet@news.onet.pl
NNTP-Posting-Date: Sun, 8 Oct 2006 18:20:57 +0000 (UTC)
X-Sender: 5Da2qcG7AWj7WISFX859Php/OS6q4VnB
In-Reply-To: <egas2q$1rr$1@news.task.gda.pl>
User-Agent: Thunderbird 1.5.0.7 (Windows/20060909)
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit