Thread View: pl.comp.lang.ruby
8 messages
8 total messages
Started by Rafał Komorowski
Sat, 07 Oct 2006 19:58
Jak dodać własną metodę typu nazwa! do klasy?
Author: Rafał Komorowski
Date: Sat, 07 Oct 2006 19:58
Date: Sat, 07 Oct 2006 19:58
33 lines
1644 bytes
1644 bytes
Nie spodziewam się pozytywnej odpowiedzi na poniższe pytanie, ale wolę spróbować. Chcę rozszerzyć funkcjonalność klasy Float o kilka brakujących metod. Działa mi takie coś: class Float # zaokrągla liczbę typu Float do jednego miejsca po przecinku def round01 (self*10).round / 10.0 end end I fajnie. Ale marzy mi się napisanie także metody round01!, która zaokrągla liczbę "in place". Żeby można było napisać: a=3.1415 a.round01! Zdaje się, że jest to niemożliwe, bo klasa Float nie jest zaimplementowana w Rubym. Próba typu: def round01! self = (self*10).round / 10.0 end kończy się porażką, ponieważ wartość self jest tylko do odczytu. Czy dobrze myślę, że nie da się tego zrobić bez grzebania w implementacji klasy Float? -- komor_newsNO@macSPAM.com
Re: Jak dodać własną metodę typu nazwa! do klasy?
Author: Marcin Mielżyński
Date: Sat, 07 Oct 2006 21:38
Date: Sat, 07 Oct 2006 21:38
34 lines
1644 bytes
1644 bytes
Tutaj chodzi chyba spójność z Fixnumem. Pomimo że Float nie jest
immediate value - jest immutable. Choć z definicji:
struct RFloat {
struct RBasic basic;
double value;
};
wynikałoby że jest mutable.
najmniej można zrobić z Fixnumami bo jego instancje to poprostu 4 (lub 8
na 64 bitowych platformach) bajtów w pamięci z ustawionym najmłodszym
bitem - więc nie mają składowej basic a przez to nie mają składowej
klass, ...wogóle nic nie mają i nie można zrobić np tak:
class << 1
end
: no virtual class for Fixnum (TypeError)
tutaj jest algorytm dekodowania typów Rubiego:
http://www.oreillynet.com/ruby/blog/2006/01/the_ruby_value_1.html
...Najlepiej zrób kompozycje.
lopex
Re: Jak dodać własną metodę typu nazwa! do klasy?
Author: Rafał Komorowski
Date: Sat, 07 Oct 2006 23:25
Date: Sat, 07 Oct 2006 23:25
41 lines
2357 bytes
2357 bytes
On 2006-10-07 23:38:50 +0200, Marcin Mielżyński <lopx@gazeta.pl> said:
> Tutaj chodzi chyba spójność z Fixnumem. Pomimo że Float nie jest
> immediate value - jest immutable.
Dzięki, wydaje mi się, że zrozumiałem :-)
> tutaj jest algorytm dekodowania typów Rubiego:
> http://www.oreillynet.com/ruby/blog/2006/01/the_ruby_value_1.html
Bardzo ciekawy artykulik. Dobrze, że coraz więcej jest bardziej
zaawansowanych materiałów o Rubym, idziemy do przodu! :-)
> ...Najlepiej zrób kompozycje.
Co masz na myśli? "aggregation" w sensie railsowym?
A tak ogólnie, w klasach wbudowanych w Rubiego bardzo brakuje mi paru
dość oczywistych funkcji, w tym właśnie zaokrąglania floata do zadanego
miejsca po przecinku. Szkoda takie podstawowe rzeczy implementować już
w interpretowanym kodzie, do tego przecież właśnie dobrze nadaje się
kompilowane C.
Ponadto chciałbym też mieć sprintf, które generuje przecinek jako
decimal-point i kropkę jako thousands-separator, ale to już z innej
beczki. Z braku lepszego pomysłu mam po prostu:
class Fixnum
def format00
sprintf("%d", self).gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1.")
end
end
ale serce mi się kraje, jak widzę wyrażenia regularne zastosowane do
tak prymitywnych rzeczy. Może jednak warto nauczyć się robić wstawkę w
C do kodu Rubiego? Nie interesowałem się tym na razie, ale widzę, że w
"biblii" jest to szeroko opisane.
--
komor_newsNO@macSPAM.com
Re: Jak dodać własną metodę typu nazwa! do klasy?
Author: Marcin Mielżyński
Date: Sun, 08 Oct 2006 00:04
Date: Sun, 08 Oct 2006 00:04
97 lines
3615 bytes
3615 bytes
Rafał Komorowski wrote:
> Bardzo ciekawy artykulik. Dobrze, że coraz więcej jest bardziej
> zaawansowanych materiałów o Rubym, idziemy do przodu! :-)
>
najlepszy materiał to http://rhg.rubyforge.org/ - szkoda że tylko część
jest przetłumaczona na angielski, plus oczywiście źródła.
na szybko zrobiłem rozszerzenie z tą metodą round01 - działa bez problemu:
mutfloat.c:
#include "ruby.h"
static VALUE
round01(num)
VALUE num;
{
double val = RFLOAT(num)->value;
if (val > 0.0) val = floor(val+0.5);
if (val < 0.0) val = ceil(val-0.5);
RFLOAT(num)->value = val;
return num;
}
void Init_Mutfloat(){
rb_define_method(rb_cFloat, "round01!", round01, 0);
}
gcc -shared mutfloat.c -lruby -o MutFloat.so
można też wcisnać do numeric.c - będzie wtedy pełen built-in
require 'Mutfloat.so' # to jeśli nie built-in
b = a = 1.3
p a.round01!
p b
i tego właśnie Matz chciał pewnie uniknąć...
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.
>> ...Najlepiej zrób kompozycje.
>
> Co masz na myśli? "aggregation" w sensie railsowym?
>
> A tak ogólnie, w klasach wbudowanych w Rubiego bardzo brakuje mi paru
> dość oczywistych funkcji, w tym właśnie zaokrąglania floata do zadanego
> miejsca po przecinku. Szkoda takie podstawowe rzeczy implementować już w
> interpretowanym kodzie, do tego przecież właśnie dobrze nadaje się
> kompilowane C.
> Ponadto chciałbym też mieć sprintf, które generuje przecinek jako
> decimal-point i kropkę jako thousands-separator, ale to już z innej
> beczki. Z braku lepszego pomysłu mam po prostu:
>
> class Fixnum
> def format00
> sprintf("%d", self).gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1.")
> end
> end
>
> ale serce mi się kraje, jak widzę wyrażenia regularne zastosowane do tak
> prymitywnych rzeczy. Może jednak warto nauczyć się robić wstawkę w C do
> kodu Rubiego? Nie interesowałem się tym na razie, ale widzę, że w
> "biblii" jest to szeroko opisane.
>
>
wszystko jest ;)
puts "%.3f" % 12.5234
z wypełnionymi spacjami: "%10.3f" % 12.5234
i wyrównane do lewej: "%-10.3f" % 12.5234
jest do tego pełna dokumentacja String#sprintf i String#%
albo po prostu:
man sprintf
jest też fajny man online:
http://man.splitbrain.org/sprintf
po co wymyślać koło....
lopex
Re: Jak dodać własną metodę typu nazwa! do klasy?
Author: Rafał Komorowski
Date: Sun, 08 Oct 2006 12:48
Date: Sun, 08 Oct 2006 12:48
69 lines
3658 bytes
3658 bytes
On 2006-10-08 02:04:00 +0200, Marcin Mielżyński <lopx@gazeta.pl> said: > na szybko zrobiłem rozszerzenie z tą metodą round01 - działa bez problemu: Jesteś niesamowity :-) Dzięki, spróbuję to wsadzić do swojego kodu. Oczywiście takie wstawki mają tę wadę, że trzeba to też wpychać na serwery produkcyjne, co może być problematyczne, jeśli nie ma się pełnej kontroli nad takim serwerem, ale na razie ten problem mi nie grozi. > 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. 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 (pomijam problem wykrzyknika). Oczywiście gdyby takie coś miało trafić do języka, to musiałoby być bardziej ogólne, czyli np. przyjmować argument decydujący o ilości miejsc po przecinku. 3.1465.round(3) => 3.147 > 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? >> ale serce mi się kraje, jak widzę wyrażenia regularne zastosowane do >> tak prymitywnych rzeczy. Może jednak warto nauczyć się robić wstawkę w >> C do kodu Rubiego? Nie interesowałem się tym na razie, ale widzę, że w >> "biblii" jest to szeroko opisane. > > wszystko jest ;) > > puts "%.3f" % 12.5234 Chyba się nie zrozumieliśmy. Mi chodzi o to, żeby zgodnie z zasadami języka polskiego (i nie tylko) _przecinek_ robił za "decimal-point", a _kropka_ jako "thousands-separator", czyli dokładnie odwrotnie niż w języku angielskim. Żeby zamiast formatowania typu: 12,345,678.99 $ otrzymać w prosty sposób: 12.345.678,99 zł :-) Czy to jest możliwe w standardowym sprintf? Z tego co przejrzałem to ani w C ani w Rubym nie ma takiej możliwości wprost? -- komor_newsNO@macSPAM.com
Re: Jak dodać własną metodę typu nazwa! do klasy?
Author: Wojciech Piekutowski
Date: Sun, 08 Oct 2006 14:56
Date: Sun, 08 Oct 2006 14:56
37 lines
2491 bytes
2491 bytes
Hej,
Rafał Komorowski wrote:
>
> A tak ogólnie, w klasach wbudowanych w Rubiego bardzo brakuje mi paru
> dość oczywistych funkcji, w tym właśnie zaokrąglania floata do zadanego
> miejsca po przecinku. Szkoda takie podstawowe rzeczy implementować już w
> interpretowanym kodzie, do tego przecież właśnie dobrze nadaje się
> kompilowane C.
> Ponadto chciałbym też mieć sprintf, które generuje przecinek jako
> decimal-point i kropkę jako thousands-separator, ale to już z innej
> beczki. Z braku lepszego pomysłu mam po prostu:
>
> class Fixnum
> def format00
> sprintf("%d", self).gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1.")
> end
> end
>
> ale serce mi się kraje, jak widzę wyrażenia regularne zastosowane do tak
> prymitywnych rzeczy. Może jednak warto nauczyć się robić wstawkę w C do
> kodu Rubiego? Nie interesowałem się tym na razie, ale widzę, że w
> "biblii" jest to szeroko opisane.
>
Z ciekawości zajrzałem do mana:
http://unixhelp.ed.ac.uk/CGI/man-cgi?sprintf+3
Jest tam info, że generowanie tych znaków zależy od ustawienia LOCALE na
odpowiednią wartość. W Twoim przypadku pl_PL lub pl_PL.UTF8 (jeśli
używasz unicode w systemie). Można też zmienić tylko poszczególne
składowe pakietu lokalizacyjnego - sam znak separacji i grupowania.
Więcej informacji znajdziesz tutaj:
http://linuxreviews.org/man/locale/index.html.pl
Pozdrawiam,
Wojciech Piekutowski
Re: Jak dodać własną metodę typu nazwa! do klasy?
Author: 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
Re: Jak dodać własną metodę typu nazwa! do klasy?
Author: Rafał Komorowski
Date: Sun, 08 Oct 2006 20:03
Date: Sun, 08 Oct 2006 20:03
21 lines
1617 bytes
1617 bytes
On 2006-10-08 16:56:05 +0200, Wojciech Piekutowski <w.piekutowski@gmail.com> said: > Z ciekawości zajrzałem do mana: > http://unixhelp.ed.ac.uk/CGI/man-cgi?sprintf+3 > > Jest tam info, że generowanie tych znaków zależy od ustawienia LOCALE > na odpowiednią wartość. Hm... A co jak się nie używa Linuxa? :-) Fajnie byłoby, gdyby jednak Ruby zachował w miarę pełną przenośność, niezależnie od platformy. Skoro już w tym wątku pofolgowaliśmy sobie i piszemy (tzn. Lopex pisze) rozszerzenia Rubiego w C, to można też lekko zhakować sobie źródło do Kernel::sprintf :-) -- komor_newsNO@macSPAM.com
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads