|
Archives
D Programming
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.ide
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger
D.gnu
D
C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows
digitalmars.empire
digitalmars.DMDScript
electronics
|
digitalmars.D.announce - Re: dmd 2.029 release
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest it and its new
Phobos2. While I explore Phobos I'll probably post some comments/bugs around
here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features-in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
int _x;
int x() const { return this._x; }
Joules opMul(Seconds s) {
return Joules(this._x * s.x);
}
string toString() { return format("Watts(%s)", this._x); }
}
struct Seconds {
int _x;
int x() const { return this._x; }
Joules opMul(Watts w) {
return Joules(this._x * w.x);
}
string toString() { return format("Seconds(%s)", this._x); }
}
struct Joules {
int _x;
int x() const { return this._x; }
string toString() { return format("Joules(%s)", this._x); }
}
auto map(alias f, TySeq1, TySeq2)(TySeq1 a1, TySeq2 a2) {
assert(a1.length == a2.length);
auto result = new typeof( f(a1[0], a2[0]) )[a1.length];
for (int i; i < a1.length; i++)
result[i] = f(a1[i], a2[i]);
return result;
}
void main() {
auto watts = [Watts(2), Watts(3), Watts(4)];
writeln(watts);
auto secs = [Seconds(5), Seconds(6), Seconds(7)];
writeln(secs);
auto result = map!( (x, y){ return x*y; } )(watts, secs);
writeln(result);
}
Few notes:
- Lacking struct inheritance I have duplicated code.
- This whole proggy is not difficult to write. It's simpler than the C++ one.
But I think it's a bit less general.
- Here I have not used const in input arguments yet, nor the map of Phobos2.
- (x, y){ return x*y; } is one of the new template literals. Can I define it
elsewhere, like in an alias? So far I have failed doing that.
Two things to improve:
1) All structs must have a default built-in opString, a good representation can
be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better than the current
one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most times is just
noise)
2) The output of that program is:
Watts(2) Watts(3) Watts(4)
Seconds(5) Seconds(6) Seconds(7)
Joules(10) Joules(18) Joules(28)
I think a much better output is:
[Watts(2), Watts(3), Watts(4)]
[Seconds(5), Seconds(6), Seconds(7)]
[Joules(10), Joules(18), Joules(28)]
Note the space after the comma, it's a small detail but it improves readability
significantly.
(This representation doesn't tell apart dynamic arrays from static ones, but I
can live with this).
----------------
I don't remember if vector ops support user-defined opMul too, I have tried
this code, but maybe I am doing something wrong:
...
Joules[3] result2;
result2[] = watts[] * secs[];
writeln(result2);
}
Bye,
bearophile
bearophile wrote:
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest it and its
new Phobos2. While I explore Phobos I'll probably post some comments/bugs
around here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features-in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
int _x;
int x() const { return this._x; }
Joules opMul(Seconds s) {
return Joules(this._x * s.x);
}
string toString() { return format("Watts(%s)", this._x); }
}
struct Seconds {
int _x;
int x() const { return this._x; }
Joules opMul(Watts w) {
return Joules(this._x * w.x);
}
string toString() { return format("Seconds(%s)", this._x); }
}
struct Joules {
int _x;
int x() const { return this._x; }
string toString() { return format("Joules(%s)", this._x); }
}
auto map(alias f, TySeq1, TySeq2)(TySeq1 a1, TySeq2 a2) {
assert(a1.length == a2.length);
auto result = new typeof( f(a1[0], a2[0]) )[a1.length];
for (int i; i < a1.length; i++)
result[i] = f(a1[i], a2[i]);
return result;
}
void main() {
auto watts = [Watts(2), Watts(3), Watts(4)];
writeln(watts);
auto secs = [Seconds(5), Seconds(6), Seconds(7)];
writeln(secs);
auto result = map!( (x, y){ return x*y; } )(watts, secs);
writeln(result);
}
Few notes:
- Lacking struct inheritance I have duplicated code.
- This whole proggy is not difficult to write. It's simpler than the C++ one.
But I think it's a bit less general.
- Here I have not used const in input arguments yet, nor the map of Phobos2.
- (x, y){ return x*y; } is one of the new template literals. Can I define it
elsewhere, like in an alias? So far I have failed doing that.
Two things to improve:
1) All structs must have a default built-in opString, a good representation
can be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better than the
current one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most times is just
noise)
No!
<rant>
toString() is one of the most dreadful features in D. Trying to slightly
improve it is a waste of time -- the whole concept needs to be redone.
It's horribly inflexible, tedious, and hugely inefficient. What more
could there be to hate?
- the object being called has no context. It doesn't know what format is
desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int! You
can't do left-align, pad with zeros, include + sign, display in hex.
- it's got no stream concept. Every object has to create and manage its
own buffer, and nobody knows if anyone actually needs it.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant string
is just going to be written to a file anyway.
I'd like to see version(debug) {} put around Object.toString(). It's a
deathtrap feature that's got no business being used other than for
debugging.
</rant>
2) The output of that program is:
Watts(2) Watts(3) Watts(4)
Seconds(5) Seconds(6) Seconds(7)
Joules(10) Joules(18) Joules(28)
I think a much better output is:
[Watts(2), Watts(3), Watts(4)]
[Seconds(5), Seconds(6), Seconds(7)]
[Joules(10), Joules(18), Joules(28)]
Note the space after the comma, it's a small detail but it improves
readability significantly.
(This representation doesn't tell apart dynamic arrays from static ones, but I
can live with this).
----------------
I don't remember if vector ops support user-defined opMul too, I have tried
this code, but maybe I am doing something wrong:
...
Joules[3] result2;
result2[] = watts[] * secs[];
writeln(result2);
}
Bye,
bearophile
No!
<rant>
toString() is one of the most dreadful features in D. Trying to slightly
improve it is a waste of time -- the whole concept needs to be redone.
It's horribly inflexible, tedious, and hugely inefficient. What more
could there be to hate?
Hey, it's only meant for debugging! (At least I hope.)
Don wrote:
I'd like to see version(debug) {} put around Object.toString(). It's a
deathtrap feature that's got no business being used other than for
debugging.
That actually sounds like a good idea. Like you say, is has no use
outside of debugging, but while debugging, it's quite useful.
--
Simen
On Thu, 23 Apr 2009 16:20:03 +0400, Don <nospam nospam.com> wrote:
bearophile wrote:
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest it and
its new Phobos2. While I explore Phobos I'll probably post some
comments/bugs around here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features-in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using
Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
int _x;
int x() const { return this._x; }
Joules opMul(Seconds s) {
return Joules(this._x * s.x);
}
string toString() { return format("Watts(%s)", this._x); }
}
struct Seconds {
int _x;
int x() const { return this._x; }
Joules opMul(Watts w) {
return Joules(this._x * w.x);
}
string toString() { return format("Seconds(%s)", this._x); }
}
struct Joules {
int _x;
int x() const { return this._x; }
string toString() { return format("Joules(%s)", this._x); }
}
auto map(alias f, TySeq1, TySeq2)(TySeq1 a1, TySeq2 a2) {
assert(a1.length == a2.length);
auto result = new typeof( f(a1[0], a2[0]) )[a1.length];
for (int i; i < a1.length; i++)
result[i] = f(a1[i], a2[i]);
return result;
}
void main() {
auto watts = [Watts(2), Watts(3), Watts(4)];
writeln(watts);
auto secs = [Seconds(5), Seconds(6), Seconds(7)];
writeln(secs);
auto result = map!( (x, y){ return x*y; } )(watts, secs);
writeln(result);
}
Few notes:
- Lacking struct inheritance I have duplicated code.
- This whole proggy is not difficult to write. It's simpler than the
C++ one. But I think it's a bit less general.
- Here I have not used const in input arguments yet, nor the map of
Phobos2.
- (x, y){ return x*y; } is one of the new template literals. Can I
define it elsewhere, like in an alias? So far I have failed doing that.
Two things to improve:
1) All structs must have a default built-in opString, a good
representation can be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better than the
current one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most times is
just noise)
No!
<rant>
toString() is one of the most dreadful features in D. Trying to slightly
improve it is a waste of time -- the whole concept needs to be redone.
It's horribly inflexible, tedious, and hugely inefficient. What more
could there be to hate?
- the object being called has no context. It doesn't know what format is
desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int! You
can't do left-align, pad with zeros, include + sign, display in hex.
- it's got no stream concept. Every object has to create and manage its
own buffer, and nobody knows if anyone actually needs it.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant string
is just going to be written to a file anyway.
Absolutely agree, but Sink is not good, either. I have previously suggested the
following design (but can't find my post anymore):
A signature of toString() should be as follows:
char[] toString(string format = null, char[] buffer = null);
Bonuses you get from that:
You don't have to change your code (aside from toString() returning mutable
array now, but it is very easy to fix)
It allows you to avoid allocations - just pass a temporary buffer to use!
It allows you to use advanced formatting options
Example:
class Number {
private int _number;
char[] toString(string format = null, char[] buffer = null) {
Format format = Format.Decimal;
switch (format) {
case "x": format = Format.Hexademical;
case "X": format = Format.HexademicalUpperCase;
case "b": format = Format.Binary;
// ...
}
return formatInteger(_number, format, buffer);
}
static char[] formatInteger(int value, Format format, char[] buffer)
{
// writes to buffer, resizing it
}
}
Cons: printf-style formatting works badly with this desing.
I belive it should be dropped anyway, in favor of a more flexible .NET-style
formatting:
writefln("My name is {} and I'm 0x{X} years old", Denis, 22);
// calls name.toString("", buffer) and age.toString("X", buffer)
Result: My name is Denis and I'm 0x16 years old.
Here is another example:
MyArray myArray = new MyArray(10, 20, 30);
char[1024] buffer;
string.format(buffer, "Array contents: [{{X}, }]", myArray);
// calls myArray.toString("{X}, ", buffer); which in turn calls
element.toString("X", buffer) on its elements and uses ", " as a separator:
Result: Array contents: [A, 14, 1E]
No allocation involved!
Denis Koroskin wrote:
On Thu, 23 Apr 2009 16:20:03 +0400, Don <nospam nospam.com> wrote:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant string
is just going to be written to a file anyway.
Absolutely agree, but Sink is not good, either. I have previously suggested
the following design (but can't find my post anymore):
A signature of toString() should be as follows:
char[] toString(string format = null, char[] buffer = null);
Bonuses you get from that:
You don't have to change your code (aside from toString() returning mutable
array now, but it is very easy to fix)
It allows you to avoid allocations - just pass a temporary buffer to use!
It'll still allocate if the buffer isn't big enough.
I usually define something like "void streamTo(Sink sink)" in a base class if I
want non-allocating output. Adding a format string to the parameter list should
be easy, but I haven't needed it yet.
I then usually implement toString by passing an appending Sink to that method,
just so Tango's formatting methods will be able to use it.
IMHO It'd be pretty nice for the standard formatting systems (both the Tango
and
Phobos ones) to just call a standard Object method taking (Sink sink, char[]
format = null) on objects.
Backward compatibility might be tricky though, if you want to support both
overriding and calling of toString(). (You can't have the default toString
implementation call the format function *and* have the default format function
implementation call toString)
Though I suppose you could take a delegate to toString in the default format
method and see if the function pointer in it points to Object.toString, just
calling sink(this.classinfo.name) if so (to emulate current behavior), and
calling toString() if not...
(Or maybe the other way around; have Object.toString check if the format
function was overridden, call it if so and return the classname if not)
Frits van Bommel wrote:
I usually define something like "void streamTo(Sink sink)" in a base
class if I want non-allocating output. Adding a format string to the
parameter list should be easy, but I haven't needed it yet.
I then usually implement toString by passing an appending Sink to that
method, just so Tango's formatting methods will be able to use it.
Yah. The way std.format does it is by operating on an abstract output
range, and then have Appender!(T[]) implement the output range
interface. So getting stringizing is as easy as passing an
Appender!string in there.
IMHO It'd be pretty nice for the standard formatting systems (both the
Tango and Phobos ones) to just call a standard Object method taking
(Sink sink, char[] format = null) on objects.
Probably we'll need that. You forgot the "in" though :o).
Andrei
Andrei Alexandrescu wrote:
Frits van Bommel wrote:
IMHO It'd be pretty nice for the standard formatting systems (both the
Tango and Phobos ones) to just call a standard Object method taking
(Sink sink, char[] format = null) on objects.
Probably we'll need that. You forgot the "in" though :o).
That's just because I'm thinking in D1, where it's optional :).
Sink is okay, but most my usages belong to one of the two scenarios:
1) I need a string representation of an Object - how is Sink useful here? I
just want to call obj.toString() and get the result
2) I need to print it to stdout, thus I call writeln/Stdout(obj); - Sink is of
no use here again.
Needs simple converter code, that safe you from typing trivial stuff
like this:
toString((char[] s) { writeln(s); });
void toString(Sink sink, string format = null) {
// what should I do here? How do I avoid allocations? I have to
duplicate code anyway
char[16] buffer;
buffer = std.string.format(buffer, format, _number);
sink(buffer);
The idea is to add a format() function that takes sink() for output:
std.string.format(sink, yourformat, _number);
Besides, why is it called toString(), if it doesn't give me an object's string
representation???
Should be called debug_output() or something similar.
Denis Koroskin wrote:
Sink is okay, but most my usages belong to one of the two scenarios:
1) I need a string representation of an Object - how is Sink useful
here? I just want to call obj.toString() and get the result 2) I need
to print it to stdout, thus I call writeln/Stdout(obj); - Sink is of
no use here again.
I hear you, but there are quite a few more considerations that apply.
For one, making string the common format of all objects is pretty
hamfisted. We need to integrate things like binary streams too. Second,
using string append and composing with it is bound to be inefficient,
and for multiple reasons. You can't just say that a reasonable way to
print a matrix is to call toString against it and print the resulting
string. With the temporary buffer passed-in or not, that's just a
terrible design.
But you need not fear. Converting to string will remain easy and simple,
it will only be a particular case of streaming objects out.
Andrei
Don wrote:
No!
<rant>
toString() is one of the most dreadful features in D. Trying to slightly
improve it is a waste of time -- the whole concept needs to be redone.
It's horribly inflexible, tedious, and hugely inefficient. What more
could there be to hate?
I agree.
- the object being called has no context. It doesn't know what format is
desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int! You
can't do left-align, pad with zeros, include + sign, display in hex.
- it's got no stream concept. Every object has to create and manage its
own buffer, and nobody knows if anyone actually needs it.
Yah. std.stdio and std.format already uses streaming internally to some
extent. I plan to make it entirely possible to dump a string and a
binary representation of an object to a generic stream, without having
to allocate any memory in the process.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant string
is just going to be written to a file anyway.
Yes. The way it should be is not with sink, but with the standard output
iterator method put().
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
I'd like to see version(debug) {} put around Object.toString(). It's a
deathtrap feature that's got no business being used other than for
debugging.
Well toString is ok for casual uses, but I agree that true streaming
mops the floor with it.
Andrei
Yes. The way it should be is not with sink, but with the standard output
iterator method put().
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
Eh. Is a sink callback too simple and easy to use or what?
grauzone wrote:
Yes. The way it should be is not with sink, but with the standard
output iterator method put().
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
Eh. Is a sink callback too simple and easy to use or what?
?
Andrei
Andrei Alexandrescu wrote:
grauzone wrote:
Yes. The way it should be is not with sink, but with the standard
output iterator method put().
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
Eh. Is a sink callback too simple and easy to use or what?
?
Why make it more complicated than it has to be?
Also, I don't know ranges, but your example doesn't seem to make much sense.
Andrei
grauzone wrote:
Andrei Alexandrescu wrote:
grauzone wrote:
Yes. The way it should be is not with sink, but with the standard
output iterator method put().
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
Eh. Is a sink callback too simple and easy to use or what?
?
Why make it more complicated than it has to be?
I am making it simpler.
Also, I don't know ranges, but your example doesn't seem to make much
sense.
s/but/consequently/
Andrei
Andrei Alexandrescu wrote:
grauzone wrote:
Andrei Alexandrescu wrote:
grauzone wrote:
Yes. The way it should be is not with sink, but with the standard
output iterator method put().
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
Eh. Is a sink callback too simple and easy to use or what?
?
Why make it more complicated than it has to be?
I am making it simpler.
How is it simpler?
sink(): simple delegate with the signature void delegate(char[] data);
output range: um what...? yeah, I know it has a put() method that
takes... something. What exactly is it supposed to take in your example?
Is streamOut() a method of the object to be dumped? What exact types to
T and R have? (You need the exact type if streamOut is supposed to be a
member function, and thus has to be virtual, so that you can it use like
the Object.toString method.)
Also, I don't know ranges, but your example doesn't seem to make much
sense.
s/but/consequently/
Probably. Just imagine you had to explain it to someone who's new to D.
Actually, I _am_ new to D2.0.
So, um... what is a b c and T object?
Andrei
Simen Kjaeraas wrote:
grauzone wrote:
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
So, um... what is a b c and T object?
In my opinion, this is a confusing example. I believe it was meant to be:
void streamOut(T, R)(T object, R range)
{
foreach(x; object.a) range.put(x);
range.put(object.b);
range.put(object.c);
}
So, streamOut is a free function, which it normally would not be. Now,
consider this:
struct foo {
int[] a;
bool b;
char c;
void streamOut(R)(R range) {
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
}
I believe this is what you'd normally do.
Do note that I might have misinterpreted it all, as Andrei's code would
not do what I have outlined above, I only feel it makes the most sense.
Yeah OK, but what about virtual functions? Not having it virtual is a
real disadvantage, because subclass-parts aren't automatically dumped.
What exactly is R, and why is it simpler than a Sink delegate? A Sink
delegate is as simple as it gets, and what else than a string do you
want to output? (Hint: this is probably not supposed to be a
serialization framework.)
One thing that I could imagine that put() automatically takes care of
formatting various data types into a string. Okay, where can I pass
format specifiers? What if put() can't deal with the type? Or does it
call std.string.format() anyway? Then why the indirection through the
string? Why not call format() directly? (Yes, format() needs to be able
to output using a sink instead of returning a string.)
Oh by the way, unlike a weird template, sink works with virtual methods,
too.
I have the impression Andrei wants to cast everything into ranges
instead of adhering to KISS.
--
Simen
grauzone wrote:
Simen Kjaeraas wrote:
Do note that I might have misinterpreted it all, as Andrei's code
would not do what I have outlined above, I only feel it makes the most
sense.
Yeah OK, but what about virtual functions? Not having it virtual is a
real disadvantage, because subclass-parts aren't automatically dumped.
Streaming out is a virtual function that takes a classic interface
object. (I explained that in two posts.)
What exactly is R, and why is it simpler than a Sink delegate? A Sink
delegate is as simple as it gets, and what else than a string do you
want to output? (Hint: this is probably not supposed to be a
serialization framework.)
It is simpler than a Sink delegate because the delegate is not simple;
it's simplistic. You can't use std.algorithm with a delegate, it only
accepts one type (meaning it is very inefficient if you have multiple
types to output) - it's essentially a non-design.
One thing that I could imagine that put() automatically takes care of
formatting various data types into a string. Okay, where can I pass
format specifiers? What if put() can't deal with the type? Or does it
call std.string.format() anyway? Then why the indirection through the
string? Why not call format() directly? (Yes, format() needs to be able
to output using a sink instead of returning a string.)
I'd spend more time on explaining that but I fear you want more to
convince yourself and others that output streams are no good and that
your non-design is simpler, than actually getting answers to your questions.
Oh by the way, unlike a weird template, sink works with virtual methods,
too.
I have the impression Andrei wants to cast everything into ranges
instead of adhering to KISS.
I want to adhere to KISS, and therefore I want to support output ranges
with e.g. strings and files. If you don't take the time to look at
ranges as you yourself said, then why do you spend time commenting on
them? Shouldn't things go the other way?
Andrei
Andrei Alexandrescu wrote:
grauzone wrote:
Simen Kjaeraas wrote:
Do note that I might have misinterpreted it all, as Andrei's code
would not do what I have outlined above, I only feel it makes the
most sense.
Yeah OK, but what about virtual functions? Not having it virtual is a
real disadvantage, because subclass-parts aren't automatically dumped.
Streaming out is a virtual function that takes a classic interface
object. (I explained that in two posts.)
There were a lot of posts in this thread. From what I've gathered, what
you said wasn't really concrete. Not as concrete as the sink proposals.
What exactly is R, and why is it simpler than a Sink delegate? A Sink
delegate is as simple as it gets, and what else than a string do you
want to output? (Hint: this is probably not supposed to be a
serialization framework.)
It is simpler than a Sink delegate because the delegate is not simple;
it's simplistic. You can't use std.algorithm with a delegate, it only
accepts one type (meaning it is very inefficient if you have multiple
types to output) - it's essentially a non-design.
At some point, you need to format it to a string anyway. And it's
probably not favorable to move that code into some deeply buried library
code, because then you don't have full control over formatting. Anyway,
I don't quite understand what you want to do. We were talking abou
improving toString, right?
One thing that I could imagine that put() automatically takes care of
formatting various data types into a string. Okay, where can I pass
format specifiers? What if put() can't deal with the type? Or does it
call std.string.format() anyway? Then why the indirection through the
string? Why not call format() directly? (Yes, format() needs to be
able to output using a sink instead of returning a string.)
I'd spend more time on explaining that but I fear you want more to
convince yourself and others that output streams are no good and that
your non-design is simpler, than actually getting answers to your
questions.
It's not my design, and I didn't even come up with that proposal. Come
on, I know my tone and my posts is bitchy as hell, but flaming is not
really what I'm up to.
Oh by the way, unlike a weird template, sink works with virtual
methods, too.
I have the impression Andrei wants to cast everything into ranges
instead of adhering to KISS.
I want to adhere to KISS, and therefore I want to support output ranges
with e.g. strings and files. If you don't take the time to look at
ranges as you yourself said, then why do you spend time commenting on
them? Shouldn't things go the other way?
Oh, I look at the Phobos docs as it seems necessary. But I still might
not know to the fullest how the pieces fit together and so on.
Andrei
Andrei Alexandrescu wrote:
grauzone wrote:
Simen Kjaeraas wrote:
Do note that I might have misinterpreted it all, as Andrei's code
would not do what I have outlined above, I only feel it makes the
most sense.
Yeah OK, but what about virtual functions? Not having it virtual is a
real disadvantage, because subclass-parts aren't automatically dumped.
Streaming out is a virtual function that takes a classic interface
object. (I explained that in two posts.)
What exactly is R, and why is it simpler than a Sink delegate? A Sink
delegate is as simple as it gets, and what else than a string do you
want to output? (Hint: this is probably not supposed to be a
serialization framework.)
It is simpler than a Sink delegate because the delegate is not simple;
it's simplistic. You can't use std.algorithm with a delegate, it only
accepts one type (meaning it is very inefficient if you have multiple
types to output) - it's essentially a non-design.
There are two possible use cases: serializing (to a text-based or binary
format) and formatting.
Serializing won't always fit here. For example, if you want to serialize
to XML, you need to tell the serializer when you're beginning a tag and
what to name it and when to end it. This might be possible with ranges,
but it would be awkward. Or maybe you have different concerns when
serializing in one binary format versus another. Or you're outputting
JSON, and you could view something as an array of objects or as a single
object -- you need to specify that.
Formatting is the other concern. This is a special case of
non-hierarchical serialization, for which ranges could work.
However, formatting *has* to be general. I rarely need to override a
formatting method, but I often need to access something via an interface
or base class and format it. If this does not work, then toString is
vastly superior. And to gain the benefits you're talking about, I have
to be able to pass in different output streams.
You can get the first requirement by having a method that takes a
formatting struct on Object, but then object.d depends on formatting --
this isn't a reasonable situation. object.d can at most define an
interface for a formatting method:
interface OutStream { ... }
class Object
{
...
void print (string format, OutStream stream);
}
This is still pushing it.
An alternative is to have:
void Object.print (void delegate (...) sink);
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 09:06:38 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant
string is just going to be written to a file anyway.
Yes. The way it should be is not with sink, but with the standard
output iterator method put().
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
What is the T object for?
Red herring. If streamOut is a member, no need for T.
This has to go into object.d and be part of the runtime, where std.range
doesn't exist. There is nothing stopping you from calling:
streamOut(&outputrange.put);
So I'd rather have a sink function.
It must be a sink _object_ so it can hold its own state. And it must
support put() so it integrates with statically-bound output ranges.
interface OutRange
{
void put(... a number of overloads ...);
}
And I wholeheartedly agree that we need this. I've run into many
situations where toString makes no sense.
Same here...
Andrei
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
Steven Schveighoffer wrote:
This has to go into object.d and be part of the runtime, where
std.range doesn't exist. There is nothing stopping you from calling:
streamOut(&outputrange.put);
So I'd rather have a sink function.
It must be a sink _object_ so it can hold its own state. And it must
support put() so it integrates with statically-bound output ranges.
interface OutRange
{
void put(... a number of overloads ...);
}
I see now, yes I agree (I think that was don's original request
anyways). That interface has to go in the runtime, though.
We may not be able to do this using templates... it has to be a virtual
function in Object to be on-par with toString. This means struct
interfaces are a requirement if you want to use ranges :(
We're in good shape actually. OutRange as a dynamic interface and an
implicit interface using .put against a struct will work just as well
with templates. (The template doesn't care whether obj.put(x) is a
virtual call or statically-bound call.)
Andrei
Andrei Alexandrescu wrote:
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
Steven Schveighoffer wrote:
This has to go into object.d and be part of the runtime, where
std.range doesn't exist. There is nothing stopping you from calling:
streamOut(&outputrange.put);
So I'd rather have a sink function.
It must be a sink _object_ so it can hold its own state. And it must
support put() so it integrates with statically-bound output ranges.
interface OutRange
{
void put(... a number of overloads ...);
}
I see now, yes I agree (I think that was don's original request
anyways). That interface has to go in the runtime, though.
We may not be able to do this using templates... it has to be a
virtual function in Object to be on-par with toString. This means
struct interfaces are a requirement if you want to use ranges :(
We're in good shape actually. OutRange as a dynamic interface and an
implicit interface using .put against a struct will work just as well
with templates. (The template doesn't care whether obj.put(x) is a
virtual call or statically-bound call.)
Andrei
"We may not be able to do this using templates... it has to be a virtual
function in Object to be on-par with toString."
Note that toString is a virtual method. You are proposing replacing
toString with a template. You cannot have virtual template methods.
Ergo, "new toString" would be inaccessible without the actual type, and
certainly not at runtime.
-- Daniel
Daniel Keep wrote:
Andrei Alexandrescu wrote:
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
Steven Schveighoffer wrote:
This has to go into object.d and be part of the runtime, where
std.range doesn't exist. There is nothing stopping you from calling:
streamOut(&outputrange.put);
So I'd rather have a sink function.
support put() so it integrates with statically-bound output ranges.
interface OutRange
{
void put(... a number of overloads ...);
}
anyways). That interface has to go in the runtime, though.
We may not be able to do this using templates... it has to be a
virtual function in Object to be on-par with toString. This means
struct interfaces are a requirement if you want to use ranges :(
implicit interface using .put against a struct will work just as well
with templates. (The template doesn't care whether obj.put(x) is a
virtual call or statically-bound call.)
Andrei
"We may not be able to do this using templates... it has to be a virtual
function in Object to be on-par with toString."
Note that toString is a virtual method. You are proposing replacing
toString with a template. You cannot have virtual template methods.
Ergo, "new toString" would be inaccessible without the actual type, and
certainly not at runtime.
The toStream that I have in mind is virtual and takes an interface of
type OutRange as outlined above.
Andrei
Steven Schveighoffer wrote:
As most ranges are structs (and rightfully
so, who wants to call 3 virtual functions every loop!), they would have
to be wrapped under the current compiler. Or am I missing something else?
Yes, some wrapping would have to be done. Hopefully it will simple
enough to keep things appealingly easy:
obj.toString(dynaRange(range));
Andrei
Andrei Alexandrescu wrote:
Steven Schveighoffer wrote:
So I'd rather have a sink function.
It must be a sink _object_ so it can hold its own state. And it must
support put() so it integrates with statically-bound output ranges.
interface OutRange
{
void put(... a number of overloads ...);
}
What exactly is the problem with requiring the input to the sink to be a string
(or actually const(char)[])?
Requiring an overload for every basic type + Object would be quite cumbersome
if
you had to do it every time you want to send the output somewhere else. Also,
it
wouldn't work for structs and unions...
(Unless you plan to implement a default OutRange that converts everything it
gets to strings and passes it on?)
Frits van Bommel wrote:
Andrei Alexandrescu wrote:
Steven Schveighoffer wrote:
So I'd rather have a sink function.
It must be a sink _object_ so it can hold its own state. And it must
support put() so it integrates with statically-bound output ranges.
interface OutRange
{
void put(... a number of overloads ...);
}
What exactly is the problem with requiring the input to the sink to be a
string (or actually const(char)[])?
You'd be forced to use intermediate strings for everything. I guess it's
not a huge concern.
Requiring an overload for every basic type + Object would be quite
cumbersome if you had to do it every time you want to send the output
somewhere else. Also, it wouldn't work for structs and unions...
(Unless you plan to implement a default OutRange that converts
everything it gets to strings and passes it on?)
I'm thinking of only allowing a few fundamental types and then have user
code build the rest using them.
Andrei
Andrei Alexandrescu wrote:
Yes. The way it should be is not with sink, but with the standard output
iterator method put().
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
// object.d
class Object
{
void streamOut(R)(R range);
}
No?
On Thu, 23 Apr 2009 09:06:38 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant string
is just going to be written to a file anyway.
Yes. The way it should be is not with sink, but with the standard output
iterator method put().
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
What is the T object for?
This has to go into object.d and be part of the runtime, where std.range
doesn't exist. There is nothing stopping you from calling:
streamOut(&outputrange.put);
So I'd rather have a sink function.
And I wholeheartedly agree that we need this. I've run into many
situations where toString makes no sense.
-Steve
On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
Steven Schveighoffer wrote:
This has to go into object.d and be part of the runtime, where
std.range doesn't exist. There is nothing stopping you from calling:
streamOut(&outputrange.put);
So I'd rather have a sink function.
It must be a sink _object_ so it can hold its own state. And it must
support put() so it integrates with statically-bound output ranges.
interface OutRange
{
void put(... a number of overloads ...);
}
I see now, yes I agree (I think that was don's original request anyways).
That interface has to go in the runtime, though.
We may not be able to do this using templates... it has to be a virtual
function in Object to be on-par with toString. This means struct
interfaces are a requirement if you want to use ranges :(
-Steve
Don wrote:
bearophile wrote:
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest it
and its new Phobos2. While I explore Phobos I'll probably post some
comments/bugs around here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features
in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using
Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
Two things to improve:
1) All structs must have a default built-in opString, a good
representation can be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better than
the current one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most times is
just noise)
No!
<rant>
toString() is one of the most dreadful features in D. Trying to slightly
improve it is a waste of time -- the whole concept needs to be redone.
It's horribly inflexible, tedious, and hugely inefficient. What more
could there be to hate?
- the object being called has no context. It doesn't know what format is
desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int! You
can't do left-align, pad with zeros, include + sign, display in hex.
- it's got no stream concept. Every object has to create and manage its
own buffer, and nobody knows if anyone actually needs it.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant string
is just going to be written to a file anyway.
I'd like to see version(debug) {} put around Object.toString(). It's a
deathtrap feature that's got no business being used other than for
debugging.
</rant>
First of all, printing stuff "struct.toString()" style is for two things:
o Debugging
o Small throwaway code snippets
The latter mainly being for two purposes:
o Testing quick concepts, trying out library functions, etc.
o For the newbie, when he's learning D, but not output formatting.
No "Real Program" uses this, because there you typically do proper
formatting of the output anyway, and almost never print entire structs
or objects as such. Instead, rather the information that they represent.
Second, since we have cool stuff in D, like templates, boxing, and other
advanced things, then compared to them, it should not be a big deal to
have automatic creation of toString for structs and objects. (This could
even be on-demand, i.e. unless called, the toString is not created for
an object/struct.)
Since the purpose of toString here is not Grand Style, it should suffice
to just recursively print the struct with its possible substructs, etc.
This would relieve the programmer from the entire extra work, and it
would also make objects look tidyer in source code.
Actually, this way, it would become trivial to print stuff:
myFancyStructWithInnerStructs st;
myRealCoolObject mo;
int i;
float f;
string s;
writeln(st,mo,i,f,s);
Here the programmer couldn't care less about looks and formatting, *as
long as* the output is legible and clear.
And what luxury -- not having to update the toString function each time
you change the class' structure! (That's a relief in the early stages of
the program, when everything is alive and fluid, before one settles on
the optimum structure.)
Naturally, if the programmer *does* supply a toString() method, then
that'd be used instead.
--------
Another way to do this would be to have a template function that writeln
(but not writefln) calls, which introspects the printee, and prints it.
Georg Wrede wrote:
Second, since we have cool stuff in D, like templates, boxing, and other
advanced things, then compared to them, it should not be a big deal to
have automatic creation of toString for structs and objects. (This could
even be on-demand, i.e. unless called, the toString is not created for
an object/struct.)
Since the purpose of toString here is not Grand Style, it should suffice
to just recursively print the struct with its possible substructs, etc.
This would relieve the programmer from the entire extra work, and it
would also make objects look tidyer in source code.
Did you know that this:
#!/home/andrei/bin/rdmd
import std.conv, std.stdio;
struct S1
{
int a = 42;
S2 b;
}
struct S2
{
int x = 4;
float y = 5.5;
}
void main()
{
writeln(to!string(S1()));
}
prints this
S1(42, S2(4, 5.5))
?
Andrei
Andrei Alexandrescu wrote:
Georg Wrede wrote:
Second, since we have cool stuff in D, like templates, boxing, and
other advanced things, then compared to them, it should not be a big
deal to have automatic creation of toString for structs and objects.
(This could even be on-demand, i.e. unless called, the toString is not
created for an object/struct.)
Since the purpose of toString here is not Grand Style, it should
suffice to just recursively print the struct with its possible
substructs, etc.
This would relieve the programmer from the entire extra work, and it
would also make objects look tidyer in source code.
Did you know that this:
#!/home/andrei/bin/rdmd
import std.conv, std.stdio;
struct S1
{
int a = 42;
S2 b;
}
struct S2
{
int x = 4;
float y = 5.5;
}
void main()
{
writeln(to!string(S1()));
}
prints this
S1(42, S2(4, 5.5))
Wow!
What if writeln would automatically call to!string for any object or struct?
Georg Wrede wrote:
Wow!
What if writeln would automatically call to!string for any object or
struct?
That's the plan, I didn't get around to it. I want to do it the right
way, i.e. with general streams, not strings.
Andrei
Andrei Alexandrescu wrote:
Georg Wrede wrote:
Wow!
What if writeln would automatically call to!string for any object or
struct?
That's the plan, I didn't get around to it. I want to do it the right
way, i.e. with general streams, not strings.
I'm just impressed.
Georg Wrede wrote:
Don wrote:
bearophile wrote:
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest it
and its new Phobos2. While I explore Phobos I'll probably post some
comments/bugs around here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features
in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using
Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
Two things to improve:
1) All structs must have a default built-in opString, a good
representation can be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better than
the current one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most times
is just noise)
No!
<rant>
toString() is one of the most dreadful features in D. Trying to
slightly improve it is a waste of time -- the whole concept needs to
be redone.
It's horribly inflexible, tedious, and hugely inefficient. What more
could there be to hate?
- the object being called has no context. It doesn't know what format
is desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int! You
can't do left-align, pad with zeros, include + sign, display in hex.
- it's got no stream concept. Every object has to create and manage
its own buffer, and nobody knows if anyone actually needs it.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant
string is just going to be written to a file anyway.
I'd like to see version(debug) {} put around Object.toString(). It's a
deathtrap feature that's got no business being used other than for
debugging.
</rant>
First of all, printing stuff "struct.toString()" style is for two things:
o Debugging
o Small throwaway code snippets
The latter mainly being for two purposes:
o Testing quick concepts, trying out library functions, etc.
o For the newbie, when he's learning D, but not output formatting.
No "Real Program" uses this, because there you typically do proper
formatting of the output anyway, and almost never print entire structs
or objects as such. Instead, rather the information that they represent.
How about something like BigInt? Why can't you just print it out?
BTW to everyone, 'Sink' was not a proposal. I was just saying that
almost anything's better than the current toString().
Don wrote:
Georg Wrede wrote:
Don wrote:
bearophile wrote:
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest it
and its new Phobos2. While I explore Phobos I'll probably post some
comments/bugs around here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features
in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using
Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
Two things to improve:
1) All structs must have a default built-in opString, a good
representation can be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better than
the current one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most times
is just noise)
No!
<rant>
toString() is one of the most dreadful features in D. Trying to
slightly improve it is a waste of time -- the whole concept needs to
be redone.
It's horribly inflexible, tedious, and hugely inefficient. What more
could there be to hate?
- the object being called has no context. It doesn't know what format
is desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int! You
can't do left-align, pad with zeros, include + sign, display in hex.
- it's got no stream concept. Every object has to create and manage
its own buffer, and nobody knows if anyone actually needs it.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant
string is just going to be written to a file anyway.
I'd like to see version(debug) {} put around Object.toString(). It's
a deathtrap feature that's got no business being used other than for
debugging.
</rant>
First of all, printing stuff "struct.toString()" style is for two things:
o Debugging
o Small throwaway code snippets
The latter mainly being for two purposes:
o Testing quick concepts, trying out library functions, etc.
o For the newbie, when he's learning D, but not output formatting.
No "Real Program" uses this, because there you typically do proper
formatting of the output anyway, and almost never print entire structs
or objects as such. Instead, rather the information that they represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you?
They're not stored as strings (not Janice's anyway), but I don't
understand the question.
BTW to everyone, 'Sink' was not a proposal. I was just saying that
almost anything's better than the current toString().
Georg Wrede wrote:
Don wrote:
Georg Wrede wrote:
Don wrote:
bearophile wrote:
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest it
and its new Phobos2. While I explore Phobos I'll probably post some
comments/bugs around here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features
in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using
Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
Two things to improve:
1) All structs must have a default built-in opString, a good
representation can be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better than
the current one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most times
is just noise)
No!
<rant>
toString() is one of the most dreadful features in D. Trying to
slightly improve it is a waste of time -- the whole concept needs to
be redone.
It's horribly inflexible, tedious, and hugely inefficient. What more
could there be to hate?
- the object being called has no context. It doesn't know what
format is desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int! You
can't do left-align, pad with zeros, include + sign, display in hex.
- it's got no stream concept. Every object has to create and manage
its own buffer, and nobody knows if anyone actually needs it.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant
string is just going to be written to a file anyway.
I'd like to see version(debug) {} put around Object.toString(). It's
a deathtrap feature that's got no business being used other than for
debugging.
</rant>
First of all, printing stuff "struct.toString()" style is for two
things:
o Debugging
o Small throwaway code snippets
The latter mainly being for two purposes:
o Testing quick concepts, trying out library functions, etc.
o For the newbie, when he's learning D, but not output formatting.
No "Real Program" uses this, because there you typically do proper
formatting of the output anyway, and almost never print entire
structs or objects as such. Instead, rather the information that they
represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you?
They're not stored as strings (not Janice's anyway), but I don't
understand the question.
You can write:
int a, b;
a=10; b=20;
writefln("%d %x", a, b);
I'd like to be able to write:
BigInt a, b;
a=10; b=20;
writefln("%d %x", a, b);
and have it behave exactly the same.
BTW to everyone, 'Sink' was not a proposal. I was just saying that
almost anything's better than the current toString().
Don wrote:
Georg Wrede wrote:
Don wrote:
Georg Wrede wrote:
Don wrote:
bearophile wrote:
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest
it and its new Phobos2. While I explore Phobos I'll probably post
some comments/bugs around here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features
in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using
Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
Two things to improve:
1) All structs must have a default built-in opString, a good
representation can be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better
than the current one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most
times is just noise)
No!
<rant>
toString() is one of the most dreadful features in D. Trying to
slightly improve it is a waste of time -- the whole concept needs
to be redone.
It's horribly inflexible, tedious, and hugely inefficient. What
more could there be to hate?
- the object being called has no context. It doesn't know what
format is desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int! You
can't do left-align, pad with zeros, include + sign, display in hex.
- it's got no stream concept. Every object has to create and manage
its own buffer, and nobody knows if anyone actually needs it.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant
string is just going to be written to a file anyway.
I'd like to see version(debug) {} put around Object.toString().
It's a deathtrap feature that's got no business being used other
than for debugging.
</rant>
First of all, printing stuff "struct.toString()" style is for two
things:
o Debugging
o Small throwaway code snippets
The latter mainly being for two purposes:
o Testing quick concepts, trying out library functions, etc.
o For the newbie, when he's learning D, but not output formatting.
No "Real Program" uses this, because there you typically do proper
formatting of the output anyway, and almost never print entire
structs or objects as such. Instead, rather the information that
they represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you?
They're not stored as strings (not Janice's anyway), but I don't
understand the question.
You can write:
int a, b;
a=10; b=20;
writefln("%d %x", a, b);
I'd like to be able to write:
BigInt a, b;
a=10; b=20;
writefln("%d %x", a, b);
and have it behave exactly the same.
Hmm. My idea was to only have writeln (and not writefln) be automated.
(For the small/debugging purpose.)
Andrei seems to be at this, but right now I don't know enough details to
say anything. It seems to be an even bigger thing than what I suggested,
and knowing he does things in a universal way, one would assume that if
a class "wants" to be printed in some way, then maybe there'll be some
provisions for it.
But, things like BigInt, that really are classes or structs that have to
be printed in a specific way, I have a hard time figuring out how to
printe them using write_f_ln.
One way would be to have the format specification (as in "%x") be
somehow passed to the toString of the struct/class. Then the class could
decide for itself how to be printed in this case.
But even this is stretching it a bit, since some more complicated
class/struct might need a more elaborate hint than just one letter. And
by that time the whole thing starts to crumble, in usability issues, at
least.
One thing we sholuld be wary of is overdesign. BigInt is ok, but by the
time we try to include a class called CompleteSimulationOfAnF1RaceCar,
we're screwed. :-) I see no way to incorporate them into writefln or
even plain writeln. Or at least, no *use*.
Georg Wrede wrote:
Don wrote:
Georg Wrede wrote:
Don wrote:
Georg Wrede wrote:
Don wrote:
bearophile wrote:
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest
it and its new Phobos2. While I explore Phobos I'll probably post
some comments/bugs around here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features
in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using
Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
Two things to improve:
1) All structs must have a default built-in opString, a good
representation can be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better
than the current one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most
times is just noise)
No!
<rant>
toString() is one of the most dreadful features in D. Trying to
slightly improve it is a waste of time -- the whole concept needs
to be redone.
It's horribly inflexible, tedious, and hugely inefficient. What
more could there be to hate?
- the object being called has no context. It doesn't know what
format is desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int!
You can't do left-align, pad with zeros, include + sign, display
in hex.
- it's got no stream concept. Every object has to create and
manage its own buffer, and nobody knows if anyone actually needs it.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all
your strings in, even if there are 200 million of them and your
giant string is just going to be written to a file anyway.
I'd like to see version(debug) {} put around Object.toString().
It's a deathtrap feature that's got no business being used other
than for debugging.
</rant>
First of all, printing stuff "struct.toString()" style is for two
things:
o Debugging
o Small throwaway code snippets
The latter mainly being for two purposes:
o Testing quick concepts, trying out library functions, etc.
o For the newbie, when he's learning D, but not output formatting.
No "Real Program" uses this, because there you typically do proper
formatting of the output anyway, and almost never print entire
structs or objects as such. Instead, rather the information that
they represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you?
They're not stored as strings (not Janice's anyway), but I don't
understand the question.
You can write:
int a, b;
a=10; b=20;
writefln("%d %x", a, b);
I'd like to be able to write:
BigInt a, b;
a=10; b=20;
writefln("%d %x", a, b);
and have it behave exactly the same.
Hmm. My idea was to only have writeln (and not writefln) be automated.
(For the small/debugging purpose.)
Andrei seems to be at this, but right now I don't know enough details to
say anything. It seems to be an even bigger thing than what I suggested,
and knowing he does things in a universal way, one would assume that if
a class "wants" to be printed in some way, then maybe there'll be some
provisions for it.
But, things like BigInt, that really are classes or structs that have to
be printed in a specific way, I have a hard time figuring out how to
printe them using write_f_ln.
One way would be to have the format specification (as in "%x") be
somehow passed to the toString of the struct/class. Then the class could
decide for itself how to be printed in this case.
But even this is stretching it a bit, since some more complicated
class/struct might need a more elaborate hint than just one letter. And
by that time the whole thing starts to crumble, in usability issues, at
least.
One thing we sholuld be wary of is overdesign. BigInt is ok, but by the
time we try to include a class called CompleteSimulationOfAnF1RaceCar,
we're screwed. :-) I see no way to incorporate them into writefln or
even plain writeln. Or at least, no *use*.
I think it'd be reasonable to limit things to the options available for
built-in types. Outside of that, custom formatting functions make a lot
of sense. The problem is that toString() _looks_ like it emulates
built-in formatting, but it only does '%s'. So it's really beguiling.
BTW, when passing the output to a sink, it should be possible to (say)
format your members with '%x' format, but you can't do that by
permanently altering sink: it should revert to its previous value once
you've sunk your last member. (I think this C++ iostreams got this wrong).
Don wrote:
Georg Wrede wrote:
One thing we sholuld be wary of is overdesign. BigInt is ok, but by
the time we try to include a class called
CompleteSimulationOfAnF1RaceCar, we're screwed. :-) I see no way to
incorporate them into writefln or even plain writeln. Or at least, no
*use*.
I think it'd be reasonable to limit things to the options available for
built-in types. Outside of that, custom formatting functions make a lot
of sense. The problem is that toString() _looks_ like it emulates
built-in formatting, but it only does '%s'. So it's really beguiling.
Heh, one thought is, suppose we could have arbitrary format
specifications in writef. Say, if we wrote %&lkjasdf; this string would
be passed to toString. (It would of course be up to the class to
error-check the string, writefln obviously cant (or shouldn't) do it.)
So, things are doable. But I'm really not looking forward to that kind
of sports. Any elaborate printing or formatting should be handled
outside writefln &co.
BTW, when passing the output to a sink, it should be possible to (say)
format your members with '%x' format, but you can't do that by
permanently altering sink: it should revert to its previous value once
you've sunk your last member. (I think this C++ iostreams got this wrong).
I guess they, too, thought of making it "easier" in the wrong place.
Just because you can, doesn't mean you have to.
(OT: an excellent example of this It's Done Because We Noticed We Could
stuff is in Firefox. When a picture is a link to another page, and you
want to drag that to the tab area, the entire picture is dragged with
the mouse. Now, how the hell am I supposed to hit the small tab area
when the large picture covers half of my Firefox??
So now I have to learn to remember to grab bigger pictures near some
edge. And I really can't see *any* valid benefit for having to drag the
picture. I'd rather have it the old way, where the mouse pointer simply
changes shape, so you know you're dragging. Damn, damn...)
Georg Wrede wrote:
Don wrote:
Georg Wrede wrote:
One thing we sholuld be wary of is overdesign. BigInt is ok, but by
the time we try to include a class called
CompleteSimulationOfAnF1RaceCar, we're screwed. :-) I see no way to
incorporate them into writefln or even plain writeln. Or at least, no
*use*.
I think it'd be reasonable to limit things to the options available
for built-in types. Outside of that, custom formatting functions make
a lot of sense. The problem is that toString() _looks_ like it
emulates built-in formatting, but it only does '%s'. So it's really
beguiling.
Heh, one thought is, suppose we could have arbitrary format
specifications in writef. Say, if we wrote %&lkjasdf; this string would
be passed to toString. (It would of course be up to the class to
error-check the string, writefln obviously cant (or shouldn't) do it.)
So, things are doable. But I'm really not looking forward to that kind
of sports. Any elaborate printing or formatting should be handled
outside writefln &co.
Take a look at the formatting library for Plan 9. It’s very much like
printf & co., except it exposes enough of its internals to allow for new
formats to be added in. See the documentation (for the *nix-ported
version) at <http://swtch.com/plan9port/man/man3/print.html> and
<http://swtch.com/plan9port/man/man3/fmtinstall.html>. For example:
typedef
struct {
double r, i;
} Complex;
#pragma varargck type "X" Complex // compiler checks type-safety
int
Xfmt(Fmt *f)
{
Complex c;
c = va_arg(f−>args, Complex);
return fmtprint(f, "(%g,%g)", c.r, c.i); // can use flags here
}
main(...)
{
Complex x = (Complex){ 1.5, −2.3 };
fmtinstall('X', Xfmt);
print("x = %X\n", x);
}
With D’s type-safe variadic functions, this model can be made really
powerful.
—Joel Salomon
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
(OT: an excellent example of this It's Done Because We Noticed We
Could stuff is in Firefox. When a picture is a link to another page,
and you want to drag that to the tab area, the entire picture is
dragged with the mouse. Now, how the hell am I supposed to hit the
small tab area when the large picture covers half of my Firefox??
So now I have to learn to remember to grab bigger pictures near some
edge. And I really can't see *any* valid benefit for having to drag
the picture. I'd rather have it the old way, where the mouse pointer
simply changes shape, so you know you're dragging. Damn, damn...)
On my system, dragging the image drags a translucent copy of the image,
so I can still see where my mouse pointer is aimed. Maybe you don't
have enough colors enabled on your screen?
Sure it looks good, and the computer owner can brag to the guy in the
next cubicle, etc. But there should be some obvious or useful *purpose*
for dragging entire pictures where a mouse pointer would be clearer,
cleaner, easier for the user, and use less computer cycles.
I mean, who's such a nutcase that he forgets halfway in the dragging,
what it is he's dragging?
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
news:op.usux6bskeav7ka steves.networkengines.com...
I was never a huge fan of application themes. I don't mind a theme for
the whole system (as long as it's simple), but I don't want iTunes to look
different just because it can.
That's one of my biggest pet peeves about modern software. I can't really do
the subject justice without delving into a giant pile of expletives. But
worse still is when they decide to go and piss all over not just standard
looks, but also standard behaviors. Like how the Win build of iTunes will
still ignore/"eat" any click that brings it to the foreground. If I wanted
that behavior I'd be running a Mac.
The absolute worst of all though is when an app (*cough* skype *cough*)
decides that "close" and "the 'close' button" should mean "don't close
anything at all, but minimize to tray instead". That should be a firing
squad offense ;) Joking aside though, any of these are guaranteed ways to
make me lose any and all respect for a piece of software and its developers,
especially if they're arrogant enough to provide no way to turn such things
off.
Nick Sabalausky wrote:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
news:op.usux6bskeav7ka steves.networkengines.com...
I was never a huge fan of application themes. I don't mind a theme for
the whole system (as long as it's simple), but I don't want iTunes to look
different just because it can.
That's one of my biggest pet peeves about modern software. I can't really do
the subject justice without delving into a giant pile of expletives. But
worse still is when they decide to go and piss all over not just standard
looks, but also standard behaviors. Like how the Win build of iTunes will
still ignore/"eat" any click that brings it to the foreground. If I wanted
that behavior I'd be running a Mac.
The absolute worst of all though is when an app (*cough* skype *cough*)
decides that "close" and "the 'close' button" should mean "don't close
anything at all, but minimize to tray instead". That should be a firing
squad offense ;)
I'd be killing my IM client constantly if not for that feature. I pretty
much expect it of any application that's meant to be running for a long
time and only rarely needing user interaction (such as a bittorrent client).
Hello Christopher,
Nick Sabalausky wrote:
The absolute worst of all though is when an app (*cough* skype
*cough*) decides that "close" and "the 'close' button" should mean
"don't close anything at all, but minimize to tray instead". That
should be a firing squad offense ;)
pretty much expect it of any application that's meant to be running
for a long time and only rarely needing user interaction (such as a
bittorrent client).
yah, for some programs you rarely want to close the program but often want
to close the UI.
BCS wrote:
Hello Christopher,
Nick Sabalausky wrote:
The absolute worst of all though is when an app (*cough* skype
*cough*) decides that "close" and "the 'close' button" should mean
"don't close anything at all, but minimize to tray instead". That
should be a firing squad offense ;)
pretty much expect it of any application that's meant to be running
for a long time and only rarely needing user interaction (such as a
bittorrent client).
yah, for some programs you rarely want to close the program but often
want to close the UI.
This is one place where I think Mac OS X gets it right. It's a massive
pain to close the last document open in OpenOffice.org before opening a
new one, only to realise that now you have to sit through the loading
screen again.
-- Daniel
"BCS" <none anon.com> wrote in message
news:a6268ff50558cb92691721562e news.digitalmars.com...
Hello Christopher,
Nick Sabalausky wrote:
The absolute worst of all though is when an app (*cough* skype
*cough*) decides that "close" and "the 'close' button" should mean
"don't close anything at all, but minimize to tray instead". That
should be a firing squad offense ;)
pretty much expect it of any application that's meant to be running
for a long time and only rarely needing user interaction (such as a
bittorrent client).
yah, for some programs you rarely want to close the program but often want
to close the UI.
That's called "Minimize".
Hello Nick,
"BCS" <none anon.com> wrote in message
news:a6268ff50558cb92691721562e news.digitalmars.com...
yah, for some programs you rarely want to close the program but often
want to close the UI.
It can be, OTOH I might want the UI process killed without killing the main
program. Another point is the other side of the assertion, "you rarely want
to close the program" as in 90% of the time even when I hit the x button,
I don't actually want to close the program.
"BCS" <none anon.com> wrote in message
news:a6268ff50d58cb92d952e5b612 news.digitalmars.com...
Hello Nick,
"BCS" <none anon.com> wrote in message
news:a6268ff50558cb92691721562e news.digitalmars.com...
yah, for some programs you rarely want to close the program but often
want to close the UI.
It can be, OTOH I might want the UI process killed without killing the
main program. Another point is the other side of the assertion, "you
rarely want to close the program" as in 90% of the time even when I hit
the x button, I don't actually want to close the program.
The whole point of the 'x' button is the close the program. Always has been.
If I didn't want to close the program, I wouldn't push it. If you want to
hide/kill the UI without closing the program, that's "minimize". True,
minimizing to the taskbar doesn't kill the UI process/thread (assuming it
even is a separate process/thread), but in the rare cases where the
distinction of "UI process running/killed" actually matters, the program can
still do that through a minimize to tray. And while neither "minimize" nor
"close" truly mean "minimize to tray", clearly "minimize" is FAR closer in
both wording and behavior. Any way you look at it, having a "close" button
that doesn't "close" the app is like having a "cancel" button that prints,
or a "save" button that plays music.
Reply to Nick,
"BCS" <none anon.com> wrote in message
news:a6268ff50d58cb92d952e5b612 news.digitalmars.com...
Hello Nick,
"BCS" <none anon.com> wrote in message
news:a6268ff50558cb92691721562e news.digitalmars.com...
yah, for some programs you rarely want to close the program but
often want to close the UI.
the main program. Another point is the other side of the assertion,
"you rarely want to close the program" as in 90% of the time even
when I hit the x button, I don't actually want to close the program.
been. If I didn't want to close the program, I wouldn't push it.
Are you saying you never make mistakes? There are program out there that
90% of the time when I hit the x button it was a mistake and in that cases
I think it to be a good design to work around it. I guess if you really hate
having it not kill the app then the program could just not /have/ a x button.
If you want to hide/kill the UI without closing the program, that's
"minimize". True, minimizing to the taskbar doesn't kill the UI
process/thread (assuming it even is a separate process/thread), but in
the rare cases where the distinction of "UI process running/killed"
actually matters, the program can still do that through a minimize to
tray. And while neither "minimize" nor "close" truly mean "minimize to
tray", clearly "minimize" is FAR closer in both wording and behavior.
Any way you look at it, having a "close" button that doesn't "close"
the app is like having a "cancel" button that prints, or a "save"
button that plays music.
Your missing my point. I don't want to re-task the button but make it not
do something that most of the time is not what I want.
BCS wrote:
I guess if you
really hate having it not kill the app then the program could just not
/have/ a x button.
Your window manager does not support such windows.
Reply to Christopher,
BCS wrote:
I guess if you really hate having it not kill the app then the
program could just not /have/ a x button.
So I guess we're stuck with the no-close close button if we don't want any
way to close the app in a single click.
"BCS" <ao pathlink.com> wrote in message
news:78ccfa2d3ebc18cb92e7b8abed64 news.digitalmars.com...
Are you saying you never make mistakes? There are program out there that
90% of the time when I hit the x button it was a mistake and in that cases
I think it to be a good design to work around it.
?? Not only can I honestly say I've never had that problem, but I find the
whole idea of it very strange. Are you certain that your mouse or window
manager isn't just acting up?
I guess if you really hate having it not kill the app then the program
could just not /have/ a x button.
You've got to be kidding me, that would be just as bad. Why would I want to
have a program get rid of the standard "exit" mechanism? Whever I come
across an app like that, the first thing I do is open the task manager and
kill it, and then immediately uninstall it.
Your missing my point. I don't want to re-task the button but make it not
do something that most of the time is not what I want.
In this particular case, that's exactly the same thing. It's the
"close"/"exit" button. If it doesn't "close"/"exit" then it's been
re-tasked. Either to "minimize to tray" or to "noop" or whatever.
Hello Nick,
I guess if you really hate having it not kill the app then the
program could just not /have/ a x button.
want to have a program get rid of the standard "exit" mechanism?
If you basicly never want to exit it? (see below)
Whever I come across an app like that, the first thing I do is open
the task manager and kill it, and then immediately uninstall it.
I'll grant there are only very few cases where I want it, but in those cases
I wouldn't have the program at all unless I wanted it running *all the time*.
If I found myself killing/restarting the program more than rarely, I'd git
rid of it and find one I don't have to do that with. For those apps, I
basically
never want to actually close them (even less often than I reboot) and on
the few occasions when I do, I'm willing to do file->exit->"Yes I really
do" sequence.
As an example of a program that works this way that I'll bet you don't mind:
The volume control in the system tray. I'm not even sure if there /is/ a
way to close it all the way.
To put it objectively: say the program take 10 sec to reload and 90% of the
time (I'd bet that's low) that I click the x button, it was a mistake (bad
mouse control, reflex "go way action", whatever). From that it can take 90
seconds to close the program before tuning off the x button is a net loss
(as long as it's easy to figure out how to really kill it).
We may have to agree to disagree; I use a few programs where having the x
button kill them would be a bad thing IMHO. You disagreeing really doesn't
matter to me.
On Fri, 24 Apr 2009 14:00:19 -0400, Nick Sabalausky <a a.a> wrote:
"BCS" <none anon.com> wrote in message
news:a6268ff50d58cb92d952e5b612 news.digitalmars.com...
Hello Nick,
"BCS" <none anon.com> wrote in message
news:a6268ff50558cb92691721562e news.digitalmars.com...
yah, for some programs you rarely want to close the program but often
want to close the UI.
It can be, OTOH I might want the UI process killed without killing the
main program. Another point is the other side of the assertion, "you
rarely want to close the program" as in 90% of the time even when I hit
the x button, I don't actually want to close the program.
The whole point of the 'x' button is the close the program. Always has
been.
If I didn't want to close the program, I wouldn't push it. If you want to
hide/kill the UI without closing the program, that's "minimize". True,
minimizing to the taskbar doesn't kill the UI process/thread (assuming it
even is a separate process/thread), but in the rare cases where the
distinction of "UI process running/killed" actually matters, the program
can
still do that through a minimize to tray. And while neither "minimize"
nor
"close" truly mean "minimize to tray", clearly "minimize" is FAR closer
in
both wording and behavior. Any way you look at it, having a "close"
button
that doesn't "close" the app is like having a "cancel" button that
prints,
or a "save" button that plays music.
Yahoo messenger's X button behavior:
click on it -> "Although the main window has been closed, Yahoo! Messenger
will continue to run in the system tray..."
With a checkbox that says "Show this message in the future."
That's perfect for me. YM also has an option to automatically remove the
taskbar button when minimized (so minimized does the behavior you want it
to do).
-Steve
On Fri, 24 Apr 2009 13:54:26 +0400, Nick Sabalausky <a a.a> wrote:
"BCS" <none anon.com> wrote in message
news:a6268ff50558cb92691721562e news.digitalmars.com...
Hello Christopher,
Nick Sabalausky wrote:
The absolute worst of all though is when an app (*cough* skype
*cough*) decides that "close" and "the 'close' button" should mean
"don't close anything at all, but minimize to tray instead". That
should be a firing squad offense ;)
pretty much expect it of any application that's meant to be running
for a long time and only rarely needing user interaction (such as a
bittorrent client).
yah, for some programs you rarely want to close the program but often
want
to close the UI.
That's called "Minimize".
"Minimize" button usually minimizes the window to task bar.
Some applications provide an additional button alongside minimize and close
that minimizes to tray (Emule and others).
Some other applications minimize to tray when you hold Shift while clicking the
minimize button - Vypress chat, Download Master, Total Commander (plugin) and
others. But overall - it's very inconsistent.
I personally wish that more programs adopt Shift+Minimize -> Tray behavior,
it's easy to remember and easy to implement.
Nick Sabalausky wrote:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
news:op.usux6bskeav7ka steves.networkengines.com...
I was never a huge fan of application themes. I don't mind a theme for
the whole system (as long as it's simple), but I don't want iTunes to look
different just because it can.
That's one of my biggest pet peeves about modern software. I can't really do
the subject justice without delving into a giant pile of expletives.
It took me some serious browsing before I found a non-obtrusive skin for
gmplayer. And I hated to have to do that. It should have been the default.
But worse still is when they decide to go and piss all over not just standard
looks, but also standard behaviors. Like how the Win build of iTunes will
still ignore/"eat" any click that brings it to the foreground. If I wanted
that behavior I'd be running a Mac.
That's a good thing with many *nix GUIs. You can have several
overlapping windows, and even do stuff in the non-top ones. But they
really should respect the target GUIs way of doing things, when porting.
The absolute worst of all though is when an app (*cough* skype *cough*)
decides that "close" and "the 'close' button" should mean "don't close
anything at all, but minimize to tray instead". That should be a firing
squad offense ;) Joking aside though, any of these are guaranteed ways to
make me lose any and all respect for a piece of software and its developers,
especially if they're arrogant enough to provide no way to turn such things
off.
Yeah, the biggest motivation (next to being graphical per se) for GUIs
was uniform app behavior. That way you only would need to learn the
common basics, and then, ostensibly, you could use any new app right off
the bat. (In the bad old days, you really had to learn to use every app,
one at a time.)
It took me some serious browsing before I found a non-obtrusive skin for
gmplayer. And I hated to have to do that. It should have been the default.
AFAIK, the gmplayer GUI is deprecated. Use mplayer or smplayer. smplayer
is a GUI for mplayer that surprisingly manages to use a standard GUI,
and not some skinable specially-made media GUI bullshit, that plagues
most media players.
grauzone wrote:
It took me some serious browsing before I found a non-obtrusive skin
for gmplayer. And I hated to have to do that. It should have been the
default.
AFAIK, the gmplayer GUI is deprecated. Use mplayer or smplayer. smplayer
is a GUI for mplayer that surprisingly manages to use a standard GUI,
and not some skinable specially-made media GUI bullshit, that plagues
most media players.
Thanks!
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
I mean, who's such a nutcase that he forgets halfway in the dragging,
what it is he's dragging?
It might be useful if you accidentally start dragging the wrong thing,
and then realize because you are dragging the wrong picture/text/etc.
But my point was really: you complained that you couldn't see the target
because the picture is covering it. My experience is that I can clearly
see the target because the picture is translucent (I can see the target
"underneath" the picture).
My complaint was about doing stuff just because you can. The dragging
was just the first gross example that crossed my mind.
(I'm on a slow graphics card. Besides, it hasn't bothered me enough to
start investigating. Heck, for all I know, I could configure it away.)
"Georg Wrede" <georg.wrede iki.fi> wrote in message
news:gsrqbj$iu1$1 digitalmars.com...
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi>
wrote:
I mean, who's such a nutcase that he forgets halfway in the dragging,
what it is he's dragging?
It might be useful if you accidentally start dragging the wrong thing,
and then realize because you are dragging the wrong picture/text/etc.
But my point was really: you complained that you couldn't see the target
because the picture is covering it. My experience is that I can clearly
see the target because the picture is translucent (I can see the target
"underneath" the picture).
My complaint was about doing stuff just because you can. The dragging was
just the first gross example that crossed my mind.
(I'm on a slow graphics card. Besides, it hasn't bothered me enough to
start investigating. Heck, for all I know, I could configure it away.)
When I try to drag a group of files in Windows Explorer it makes them
translucent instead of opaque. But I *still* find it unforgivably difficult
to see underneath to where I'm dropping them. (Although maybe I can turn
that off...)
Jarrett Billingsley wrote:
On Thu, Apr 23, 2009 at 2:32 PM, Georg Wrede <georg.wrede iki.fi> wrote:
(OT: an excellent example of this It's Done Because We Noticed We Could
stuff is in Firefox. When a picture is a link to another page, and you want
to drag that to the tab area, the entire picture is dragged with the mouse.
Now, how the hell am I supposed to hit the small tab area when the large
picture covers half of my Firefox??
cubicle, etc. But there should be some obvious or useful *purpose* for
dragging entire pictures where a mouse pointer would be clearer, cleaner,
easier for the user, and use less computer cycles.
I mean, who's such a nutcase that he forgets halfway in the dragging, what
it is he's dragging?
Middle-click.
Yeah.
But I still don't see the glamouros advantages in dragging whole pictures.
And I often drag stuff to existing tabs. A good example is when browsing
http://apod.nasa.gov/apod/ap090424.html where I usually end up with a
dozen tabs in no time.
Georg Wrede wrote:
Jarrett Billingsley wrote:
I mean, who's such a nutcase that he forgets halfway in the dragging,
what
it is he's dragging?
Middle-click.
Yeah.
But I still don't see the glamouros advantages in dragging whole pictures.
And I often drag stuff to existing tabs. A good example is when browsing
http://apod.nasa.gov/apod/ap090424.html where I usually end up with a
dozen tabs in no time.
I think it's because Firefox doesn't know you're just dragging those
images to a tab. For all the browser knows, you're playing a game of
chess, and you're dragging a pawn to E5. In which case, it makes a lot
of sense for a ghost image to follow the drag behavior.
For generalized dragdrop, I think ghosted images are a good, safe guess.
Did you know you can right-click to "Open in New Tab"?
--benji
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi>
So now I have to learn to remember to grab bigger pictures near some
edge. And I really can't see *any* valid benefit for having to drag
the picture. I'd rather have it the old way, where the mouse pointer
simply changes shape, so you know you're dragging. Damn, damn...)
image, so I can still see where my mouse pointer is aimed. Maybe you
don't have enough colors enabled on your screen?
Sure it looks good, and the computer owner can brag to the guy in the
next cubicle, etc. But there should be some obvious or useful
*purpose* for dragging entire pictures where a mouse pointer would be
clearer, cleaner, easier for the user, and use less computer cycles.
I mean, who's such a nutcase that he forgets halfway in the dragging,
what it is he's dragging?
One thing that does annoy me is if you are doing this over a slow RDP
link, the eye candy isn't worth it.
I was never a huge fan of application themes. I don't mind a theme for
the whole system (as long as it's simple), but I don't want iTunes to
look different just because it can. I think it has been discussed
before that most video editors have the slickest GUI, with real-looking
knobs and "led's", but the video editing part of it is buggy as hell.
You're the first one to comment on the actual issue!!! :-)
Those video editors, iTunes and such look like they're programmed by
12-year olds. Somewhere there should be an adult saying what not to do!
I bet the guy who did this never expected that whole-picture dragging
actually uses more electricity in your computer. When every Firefox user
(and the others "who have to implement this too, so as not to look
inferior!") in the whole world drags whole pictures, the combined
increase in world electric usage rises well above his day-job salary.
Greenpeace ought to shoot him.
"Georg Wrede" <georg.wrede iki.fi> wrote in message
news:gsrrfn$kv3$1 digitalmars.com...
Those video editors, iTunes and such look like they're programmed by
12-year olds. Somewhere there should be an adult saying what not to do!
Well put.
I bet the guy who did this never expected that whole-picture dragging
actually uses more electricity in your computer. When every Firefox user
(and the others "who have to implement this too, so as not to look
inferior!") in the whole world drags whole pictures, the combined increase
in world electric usage rises well above his day-job salary.
Greenpeace ought to shoot him.
Funny, earlier today I was just thinking very much the same thing about a
video I saw a few weeks ago of Palm's WebOS (Or it might have been some
clone of WebOS). Fancy moving curves and scaling icons that serve absolutely
no purpose besides 1. "flash for the sake of flash" (I *hate* that!) and 2.
drain the battery. Which is really sad, I used to have so much respect for
Palm...But then they killed graffiti, and then replaced their PDAs with cell
phones (and we never did get PDAs with hard drives, which is ridiculous,
even my portable music player has a damn hard drive, which of course is one
device I wouldn't even need if my PDA *had a hdd!!*), and now this WebOS
garbage, sheesh...And speaking of PDAs, now Nintendo's been changing their
DS from a reasonable gaming device into the world's shittiest PDA...Man, the
world of software and consumer electronics really depresses me these days...
Nick Sabalausky wrote:
"Georg Wrede" <georg.wrede iki.fi> wrote in message
news:gsrrfn$kv3$1 digitalmars.com...
Those video editors, iTunes and such look like they're programmed by
12-year olds. Somewhere there should be an adult saying what not to do!
Well put.
I bet the guy who did this never expected that whole-picture dragging
actually uses more electricity in your computer. When every Firefox user
(and the others "who have to implement this too, so as not to look
inferior!") in the whole world drags whole pictures, the combined increase
in world electric usage rises well above his day-job salary.
Greenpeace ought to shoot him.
Funny, earlier today I was just thinking very much the same thing about a
video I saw a few weeks ago of Palm's WebOS (Or it might have been some
clone of WebOS). Fancy moving curves and scaling icons that serve absolutely
no purpose besides 1. "flash for the sake of flash" (I *hate* that!) and 2.
drain the battery. Which is really sad, I used to have so much respect for
Palm...But then they killed graffiti, and then replaced their PDAs with cell
phones (and we never did get PDAs with hard drives, which is ridiculous,
even my portable music player has a damn hard drive, which of course is one
device I wouldn't even need if my PDA *had a hdd!!*), and now this WebOS
garbage, sheesh...And speaking of PDAs, now Nintendo's been changing their
DS from a reasonable gaming device into the world's shittiest PDA...Man, the
world of software and consumer electronics really depresses me these days...
It was different in the old days. In 1981 HP introduced the HP-12c
financial calculator. Seems it's still sold, for about $60.
I'd like to see the consumer gadget introduced this year, that is still
sold in 2037.
And they're built to last. I have a few HP calculators (the earliest a
HP-25, I bought in 1975), and they're fiercely usable, sturdy, and
definitely not cluttered with unneeded "features". I still use them,
particularly the HP-28s, the HP-25, and the HP-95 (which is actually an
IBM PC in palmtop size).
On Thu, Apr 23, 2009 at 2:32 PM, Georg Wrede <georg.wrede iki.fi> wrote:
(OT: an excellent example of this It's Done Because We Noticed We Could
stuff is in Firefox. When a picture is a link to another page, and you want
to drag that to the tab area, the entire picture is dragged with the mouse.
Now, how the hell am I supposed to hit the small tab area when the large
picture covers half of my Firefox??
Sure it looks good, and the computer owner can brag to the guy in the next
cubicle, etc. But there should be some obvious or useful *purpose* for
dragging entire pictures where a mouse pointer would be clearer, cleaner,
easier for the user, and use less computer cycles.
I mean, who's such a nutcase that he forgets halfway in the dragging, what
it is he's dragging?
Middle-click.
On Thu, 23 Apr 2009 17:35:59 +0400, Frits van Bommel
<fvbommel remwovexcapss.nl> wrote:
Denis Koroskin wrote:
On Thu, 23 Apr 2009 16:20:03 +0400, Don <nospam nospam.com> wrote:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all your
strings in, even if there are 200 million of them and your giant
string is just going to be written to a file anyway.
suggested the following design (but can't find my post anymore):
A signature of toString() should be as follows:
char[] toString(string format = null, char[] buffer = null);
Bonuses you get from that:
You don't have to change your code (aside from toString() returning
mutable array now, but it is very easy to fix)
It allows you to avoid allocations - just pass a temporary buffer to
use!
It'll still allocate if the buffer isn't big enough.
Of course, it allows you to avoid allocations, but it doesn't necessarily
eliminate them.
I usually define something like "void streamTo(Sink sink)" in a base
class if I want non-allocating output. Adding a format string to the
parameter list should be easy, but I haven't needed it yet.
I then usually implement toString by passing an appending Sink to that
method, just so Tango's formatting methods will be able to use it.
IMHO It'd be pretty nice for the standard formatting systems (both the
Tango and Phobos ones) to just call a standard Object method taking
(Sink sink, char[] format = null) on objects.
Sink is okay, but most my usages belong to one of the two scenarios:
1) I need a string representation of an Object - how is Sink useful here? I
just want to call obj.toString() and get the result
2) I need to print it to stdout, thus I call writeln/Stdout(obj); - Sink is of
no use here again.
That said, I have other use-cases, too, but never once I needed a custom Sink
property.
Besides, having a Sink object is redundant and makes things more complex in
most cases. Compare:
class Number
{
private int _number;
// My version
char[] toString(string format, char[] buffer = null) {
return std.string.format(buffer, format, _number); // use default
formatter, buffer is provided to avoid allocations
}
// Your version
void toString(Sink sink, string format = null) {
// what should I do here? How do I avoid allocations? I have to
duplicate code anyway
char[16] buffer;
buffer = std.string.format(buffer, format, _number);
sink(buffer);
}
}
How is that better than using external sink? Use composition!
toString/streamOut can be implemented on top of my toString:
char[] buffer;
sink(object.toString(format, buffer)); // I believe explicit is better here
Also, this way sink is called directly an may be inlined.
Besides, why is it called toString(), if it doesn't give me an object's string
representation???
Backward compatibility might be tricky though, if you want to support
both overriding and calling of toString(). (You can't have the default
toString implementation call the format function *and* have the default
format function implementation call toString)
My version is (almost) backwards compatible.
On Thu, 23 Apr 2009 10:30:15 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
Daniel Keep wrote:
Andrei Alexandrescu wrote:
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 09:24:59 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
Steven Schveighoffer wrote:
This has to go into object.d and be part of the runtime, where
std.range doesn't exist. There is nothing stopping you from
calling:
streamOut(&outputrange.put);
So I'd rather have a sink function.
support put() so it integrates with statically-bound output ranges.
interface OutRange
{
void put(... a number of overloads ...);
}
anyways). That interface has to go in the runtime, though.
We may not be able to do this using templates... it has to be a
virtual function in Object to be on-par with toString. This means
struct interfaces are a requirement if you want to use ranges :(
implicit interface using .put against a struct will work just as well
with templates. (The template doesn't care whether obj.put(x) is a
virtual call or statically-bound call.)
Andrei
virtual
function in Object to be on-par with toString."
Note that toString is a virtual method. You are proposing replacing
toString with a template. You cannot have virtual template methods.
Ergo, "new toString" would be inaccessible without the actual type, and
certainly not at runtime.
The toStream that I have in mind is virtual and takes an interface of
type OutRange as outlined above.
OK, that's fine, I was working off your original proposal:
void streamOut(R)(R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
Of course, this then eliminates structs from being OutRange's without
having struct interfaces. As most ranges are structs (and rightfully so,
who wants to call 3 virtual functions every loop!), they would have to be
wrapped under the current compiler. Or am I missing something else?
-Steve
On Thu, 23 Apr 2009 18:28:53 +0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
Denis Koroskin wrote:
Sink is okay, but most my usages belong to one of the two scenarios: 1)
I need a string representation of an Object - how is Sink useful
here? I just want to call obj.toString() and get the result 2) I need
to print it to stdout, thus I call writeln/Stdout(obj); - Sink is of
no use here again.
I hear you, but there are quite a few more considerations that apply.
For one, making string the common format of all objects is pretty
hamfisted. We need to integrate things like binary streams too. Second,
using string append and composing with it is bound to be inefficient,
and for multiple reasons. You can't just say that a reasonable way to
print a matrix is to call toString against it and print the resulting
string. With the temporary buffer passed-in or not, that's just a
terrible design.
But you need not fear. Converting to string will remain easy and simple,
it will only be a particular case of streaming objects out.
Andrei
I'm fine with that, especially if entire Phobos will be consistent with it
(e.g. std.string.format accepts sink object etc). There a few problems with it,
though.
I like the "toStream" name but I believe it is a bit misleading - if toString()
returns a string, then toStream() should return stream, too, not accept it.
But what about custom formatting? Previously I stated that current scheme
doesn't allow them, but it turned out to be possible.
For example, you introduced custom array formatting:
%(s; ) -> array.toString("s; ", ...);
Similar approach may be used for other user-defined formatting options:
%s -> obj.toString("s");
%d -> obj.toString("d");
...
%(any_set_of_characters) -> obj.toString("any_set_of_characters"); // including
inner %() etc
Example: given an array of arrays of ints, print them as follows: "[ [1, 2, 3,
4, ]; [5, 6, 7, 8, ]; [9, a, b, c, ]; ]"
int[][] arrayOfArraysOfInts;
writefln("[ %([%(x, )]; )]", arrayOfArraysOfInts);
Just to make it more clear:
[ %([%(x, )]; )] -> "[ " ~ arrayOfArraysOfInts.toString("[%(x, )]; ") ~ "]"
On Thu, 23 Apr 2009 19:34:38 +0400, Don <nospam nospam.com> wrote:
Georg Wrede wrote:
Don wrote:
Georg Wrede wrote:
Don wrote:
Georg Wrede wrote:
Don wrote:
bearophile wrote:
This post is mostly for Andrei.
I have played with D2 a bit; probably I'll need months to digest
it and its new Phobos2. While I explore Phobos I'll probably post
some comments/bugs around here.
After reading this:
http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features
in-vc10-part-3.aspx
I have tried to write a toy implementation of it in D2 (not using
Phobos2 yet):
import std.stdio: writeln;
import std.string: format;
struct Watts {
Two things to improve:
1) All structs must have a default built-in opString, a good
representation can be:
StructName(field_value1, field_value2, field_value1, ...).
It's not a perfect textual representation, but it's WAY better
than the current one (currently it shows just the struct name).
(Printing the module name before the struct name is bad, most
times is just noise)
No!
<rant>
toString() is one of the most dreadful features in D. Trying to
slightly improve it is a waste of time -- the whole concept needs
to be redone.
It's horribly inflexible, tedious, and hugely inefficient. What
more could there be to hate?
- the object being called has no context. It doesn't know what
format is desired, for example.
- you can't emulate formatting of built-in types, NOT EVEN int!
You can't do left-align, pad with zeros, include + sign, display
in hex.
- it's got no stream concept. Every object has to create and
manage its own buffer, and nobody knows if anyone actually needs
it.
It ought to be at least as simple as:
struct Foo(A, B, C){
A[10] a;
B b;
C c;
void toString(Sink sink){
foreach(x; a) sink(x);
sink(b);
sink(c);
}
}
... but it's not, you have to create a silly buffer to put all
your strings in, even if there are 200 million of them and your
giant string is just going to be written to a file anyway.
I'd like to see version(debug) {} put around Object.toString().
It's a deathtrap feature that's got no business being used other
than for debugging.
</rant>
First of all, printing stuff "struct.toString()" style is for two
things:
o Debugging
o Small throwaway code snippets
The latter mainly being for two purposes:
o Testing quick concepts, trying out library functions, etc.
o For the newbie, when he's learning D, but not output formatting.
No "Real Program" uses this, because there you typically do proper
formatting of the output anyway, and almost never print entire
structs or objects as such. Instead, rather the information that
they represent.
How about something like BigInt? Why can't you just print it out?
?? Why couldn't you?
They're not stored as strings (not Janice's anyway), but I don't
understand the question.
You can write:
int a, b;
a=10; b=20;
writefln("%d %x", a, b);
I'd like to be able to write:
BigInt a, b;
a=10; b=20;
writefln("%d %x", a, b);
and have it behave exactly the same.
automated. (For the small/debugging purpose.)
Andrei seems to be at this, but right now I don't know enough details
to say anything. It seems to be an even bigger thing than what I
suggested, and knowing he does things in a universal way, one would
assume that if a class "wants" to be printed in some way, then maybe
there'll be some provisions for it.
But, things like BigInt, that really are classes or structs that have
to be printed in a specific way, I have a hard time figuring out how to
printe them using write_f_ln.
One way would be to have the format specification (as in "%x") be
somehow passed to the toString of the struct/class. Then the class
could decide for itself how to be printed in this case.
But even this is stretching it a bit, since some more complicated
class/struct might need a more elaborate hint than just one letter. And
by that time the whole thing starts to crumble, in usability issues, at
least.
One thing we sholuld be wary of is overdesign. BigInt is ok, but by
the time we try to include a class called
CompleteSimulationOfAnF1RaceCar, we're screwed. :-) I see no way to
incorporate them into writefln or even plain writeln. Or at least, no
*use*.
I think it'd be reasonable to limit things to the options available for
built-in types. Outside of that, custom formatting functions make a lot
of sense. The problem is that toString() _looks_ like it emulates
built-in formatting, but it only does '%s'. So it's really beguiling.
BTW, when passing the output to a sink, it should be possible to (say)
format your members with '%x' format, but you can't do that by
permanently altering sink: it should revert to its previous value once
you've sunk your last member. (I think this C++ iostreams got this
wrong).
I'm not sure Sink should know anything about formatting. It's up to class
designer to decide what custom formatters mean - they may be *very* complex.
See my other post about formatting.
On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
(OT: an excellent example of this It's Done Because We Noticed We Could
stuff is in Firefox. When a picture is a link to another page, and you
want to drag that to the tab area, the entire picture is dragged with
the mouse. Now, how the hell am I supposed to hit the small tab area
when the large picture covers half of my Firefox??
So now I have to learn to remember to grab bigger pictures near some
edge. And I really can't see *any* valid benefit for having to drag the
picture. I'd rather have it the old way, where the mouse pointer simply
changes shape, so you know you're dragging. Damn, damn...)
On my system, dragging the image drags a translucent copy of the image, so
I can still see where my mouse pointer is aimed. Maybe you don't have
enough colors enabled on your screen?
-Steve
On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi>
wrote:
(OT: an excellent example of this It's Done Because We Noticed We
Could stuff is in Firefox. When a picture is a link to another page,
and you want to drag that to the tab area, the entire picture is
dragged with the mouse. Now, how the hell am I supposed to hit the
small tab area when the large picture covers half of my Firefox??
So now I have to learn to remember to grab bigger pictures near some
edge. And I really can't see *any* valid benefit for having to drag
the picture. I'd rather have it the old way, where the mouse pointer
simply changes shape, so you know you're dragging. Damn, damn...)
image, so I can still see where my mouse pointer is aimed. Maybe you
don't have enough colors enabled on your screen?
Sure it looks good, and the computer owner can brag to the guy in the
next cubicle, etc. But there should be some obvious or useful *purpose*
for dragging entire pictures where a mouse pointer would be clearer,
cleaner, easier for the user, and use less computer cycles.
I mean, who's such a nutcase that he forgets halfway in the dragging,
what it is he's dragging?
It might be useful if you accidentally start dragging the wrong thing, and
then realize because you are dragging the wrong picture/text/etc.
But my point was really: you complained that you couldn't see the target
because the picture is covering it. My experience is that I can clearly
see the target because the picture is translucent (I can see the target
"underneath" the picture).
-Steve
On Thu, 23 Apr 2009 14:32:13 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
Steven Schveighoffer wrote:
On Thu, 23 Apr 2009 12:09:20 -0400, Georg Wrede <georg.wrede iki.fi>
wrote:
(OT: an excellent example of this It's Done Because We Noticed We
Could stuff is in Firefox. When a picture is a link to another page,
and you want to drag that to the tab area, the entire picture is
dragged with the mouse. Now, how the hell am I supposed to hit the
small tab area when the large picture covers half of my Firefox??
So now I have to learn to remember to grab bigger pictures near some
edge. And I really can't see *any* valid benefit for having to drag
the picture. I'd rather have it the old way, where the mouse pointer
simply changes shape, so you know you're dragging. Damn, damn...)
image, so I can still see where my mouse pointer is aimed. Maybe you
don't have enough colors enabled on your screen?
Sure it looks good, and the computer owner can brag to the guy in the
next cubicle, etc. But there should be some obvious or useful *purpose*
for dragging entire pictures where a mouse pointer would be clearer,
cleaner, easier for the user, and use less computer cycles.
I mean, who's such a nutcase that he forgets halfway in the dragging,
what it is he's dragging?
One thing that does annoy me is if you are doing this over a slow RDP
link, the eye candy isn't worth it.
I was never a huge fan of application themes. I don't mind a theme for
the whole system (as long as it's simple), but I don't want iTunes to look
different just because it can. I think it has been discussed before that
most video editors have the slickest GUI, with real-looking knobs and
"led's", but the video editing part of it is buggy as hell.
-Steve
On Thu, Apr 23, 2009 at 6:01 PM, Christopher Wright <dhasenan gmail.com> wr=
ote:
Andrei Alexandrescu wrote:
Yes. The way it should be is not with sink, but with the standard output
iterator method put().
void streamOut(T, R)(T object, R range)
{
=A0 =A0foreach(x; a) range.put(x);
=A0 =A0range.put(b);
=A0 =A0range.put(c);
}
// object.d
class Object
{
=A0 =A0 =A0 =A0void streamOut(R)(R range);
}
No?
No. Templated methods are not virtual.
On Thu, 23 Apr 2009 21:40:36 -0400, Christopher Wright wrote:
Nick Sabalausky wrote:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
news:op.usux6bskeav7ka steves.networkengines.com...
I was never a huge fan of application themes. I don't mind a theme
for the whole system (as long as it's simple), but I don't want iTunes
to look different just because it can.
really do the subject justice without delving into a giant pile of
expletives. But worse still is when they decide to go and piss all over
not just standard looks, but also standard behaviors. Like how the Win
build of iTunes will still ignore/"eat" any click that brings it to the
foreground. If I wanted that behavior I'd be running a Mac.
The absolute worst of all though is when an app (*cough* skype *cough*)
decides that "close" and "the 'close' button" should mean "don't close
anything at all, but minimize to tray instead". That should be a firing
squad offense ;)
I'd be killing my IM client constantly if not for that feature. I pretty
much expect it of any application that's meant to be running for a long
time and only rarely needing user interaction (such as a bittorrent
client).
I think he was referring to not having an exit. That is File->Exit is
also minimize to tray which is not the case in most such apps.
grauzone wrote:
void streamOut(T, R)(T object, R range)
{
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
So, um... what is a b c and T object?
In my opinion, this is a confusing example. I believe it was meant to be:
void streamOut(T, R)(T object, R range)
{
foreach(x; object.a) range.put(x);
range.put(object.b);
range.put(object.c);
}
So, streamOut is a free function, which it normally would not be. Now, consider
this:
struct foo {
int[] a;
bool b;
char c;
void streamOut(R)(R range) {
foreach(x; a) range.put(x);
range.put(b);
range.put(c);
}
}
I believe this is what you'd normally do.
Do note that I might have misinterpreted it all, as Andrei's code would not do
what I have outlined above, I only feel it makes the most sense.
--
Simen
|
|