Article View: pl.comp.lang.ruby
Article #224Re: Jak dodać własną metodę typu nazwa! do klasy?
From: Marcin Mielżyński
Date: Sun, 08 Oct 2006 18:20
Date: Sun, 08 Oct 2006 18:20
161 lines
5435 bytes
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-mailReferences:
<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