Qt Quarterly: A Taste of Qt 4

Qt Quarterly is a paper-based newsletter exclusively available to Trolltech's Qt customers. As a courtesy and convenience, a selection of articles are delayed also made available online in HTML format. One of the more interesting articles for KDE developers in this year's first quarter issue is an article by Jasmin Blanchette which gives "A Taste of Qt 4". A Qt 4 technology preview is expected for this summer requesting for feedback and a Qt 4 Beta is planned for the second half of 2004.

Dot Categories: 

Comments

by Niek (not verified)

I really like these:

* Qt splitted in GUI and non-GUI part
* Performance improvements
* Better integration with KDevelop
* Arthur (paint engine): perhaps a Cairo (FDO stuff, together with Keith's XServer) backend
* Scribe (text render engine) and ATK accessibility bridge: now we're on par with GTK on this stuff :)

by wow (not verified)

> Scribe (text render engine) and ATK accessibility bridge: now we're on par with GTK on this stuff :)

Erm, Qt is already on par with Pango.. The only thing missing for a while was proper Indic support which came out in Qt 3.2. Qt 3.0 had bidirectional-text support months before Gtk 2.0 came out (with Pango), and Qt 2.0 came out with full fledged Unicode support, many years before Gtk 2.0 and Pango had that.

by Ken (not verified)

> Erm, Qt is already on par with Pango..

Actually not quite. Pango deals with fonts better on linux, especially a lot of those in the cjk range. It also has a text layouting api that qt desparately needs, to handle complex line breaking and paragraphing situations.

Also, support for input methods in qt is lacking, as qt3 only really supports XIM.

So on the i18n front, gtk is still ahead overall, i would have to say

by ac (not verified)

"Pango deals with fonts better on linux, especially a lot of those in the cjk range. "

Perhaps, I don't have much experience with cjk.

"It also has a text layouting api that qt desparately needs, to handle complex line breaking and paragraphing situations."

It already has a complex text layouting API since Qt 2.0. It was mostly rewritten in 3.0 to support bidirectional text.

"Also, support for input methods in qt is lacking, as qt3 only really supports XIM"

Not true, depending on the language, there are other input methods available as Qt plugins. What thing that is lacking is IIIM support however.

by Ken (not verified)

> It already has a complex text layouting API since Qt 2.0. It was mostly rewritten in 3.0 to support bidirectional text.

Is it a public API? Last time I checked, things like QTextEdit could do it right, but when it came two writing your own widgets that needed layout, there wasn't much of a way to do it?

Also, which input method plugins were you referring to? THe only thing I know about is the 'immodule for qt' effort, but it hasn't been incorporated into qt and as far as i know there hasn't been much mention of it outside of the pages and mailing lists that are directly associated with it.

by James Richard Tyrer (not verified)

> Erm, Qt is already on par with Pango.

I can't say since I haven't used Pango lately.

However, concern about these advanced features is misplaced because the current release of Qt does not handle fonts well -- basic font handling. It fails to find a significant number of my installed fonts which even WordPerfect-8.1 finds correctly.

Test case: I have several weights and widths of Helvetica (Type1) which are simply not listed. What is worse is that this (to some extent) is a regression. I am certain that I used to use Helvetica Narrow with no problem.

Yes, I did send them a bug report and the advised me that my analysis of the problem was correct (TrueType and Type1 handle this differently) and that they would work on it.

With other fonts, Qt does find the font, but it then uses the wrong font. Considering that Qt is now in version 3.x.y this causes great concern -- in general problems like this are usually due to a naive design.

I hope that at least some of this gets fixed with 3.3.2 -- if I had paid full price for these fonts, I would not be very pleased that I can't use them in KDE.

--
JRT

by Iuri Fiedoruk (not verified)

>Better integration with KDevelop

If this is well done we can have some kind of delphi/kylix, but open source and more native! WOW!

by ac (not verified)

I love the new foreach. How is this done? moc?

by Jonathan Tan (not verified)

foreach is part of STL. I think the new QT constructs inherit from the STL containers (or at least implement the container interfaces) so we can use STL algorithms for the QT containers.

by Marc Mutz (not verified)

> foreach is part of STL. I think the new QT constructs inherit from the STL
> containers (or at least implement the container interfaces) so we can use STL
> algorithms for the QT containers.

No, you can already use STL algorithms on Qt containers since Qt 3.0 made them STL compatible:

QStringList list;
std::for_each( list.begin(), list.end(),
SomeFunctor() );

The new foreach is most probably a macro (and it will probably expand to suboptimal code (say "const vs. non-const iterators").
If it was more than that, you wouldn't need the redundant "QString s" declaration in it ("list" already has that information), so you could write:

foreach( s, list )
len += s.length();

The problem I see is that "foreach" - as an identifier - will surely clash with a possible future C++ reserved keyword of the same name. But then, the C++ people will more likely standardize the Boost Lambda library than introducing syntactic sugar in the language...

by Matthias Ettrich (not verified)

Actually, with our version of foreach you can write both. foreach(s, list) works just as well as foreach(QString s, list). It is a combination of template magic and a macro. The macro is of course called Q_FOREACH, but you can set a flag that "pollutes" the namespace with the foreach keyword if you want to.

The code it expands to isn't exactly trivial, especially not on non-gcc compilers like MSVC6. The generated assembly, however, is pretty optimal. While it is slightly bigger than a handwritten loop, there is basically no speed difference.

Would I recommend the construct to someone who knows and loves the STL? No. Would I recommend it to somebody who wants to write readable, fast-enough, and good-enough code and possibly has a Java background? Yes. Do I use it myself? In application code, yes.

by David (not verified)

"Would I recommend the construct to someone who knows and loves the STL? No. Would I recommend it to somebody who wants to write readable, fast-enough, and good-enough code and possibly has a Java background? Yes. Do I use it myself? In application code, yes."

That would be me then. Sounds great!

by El Pseudonymo (not verified)

I am quite a bit curious: Did Trolltech implement this via the moc preprocessor? If not, I can hardly imagine a way how this can be done with pure C++ and general enough so that user defined container classes will work with this. I came up so far with the snippet below, but this has its limitations as can be seen.

----------------------------------------------------------------

#define foreach(decl, container) for(std::pair::type, sizeof(deduce_helper(container))>\
::type::iterator> iter = std::make_pair(0, container.begin()); iter.second != container.end(); (iter.first = 0, ++iter.second) ) \
for(decl = *iter.second; iter.first != 1; ++iter.first)

struct std_vector_tag { char d; };
struct std_list_tag { char d[2]; };
struct std_string_tag { char d[4]; };
struct std_map_tag { char d[8]; };

template
void deduce_helper(T) { }

template
std_vector_tag deduce_helper(std::vector);

template
std_list_tag deduce_helper(std::list);

std_string_tag deduce_helper(std::string);

template
std_map_tag deduce_helper(std::map);

template
struct deduce_from_tag;

template
struct deduce_from_tag
{
typedef std::vector type;
};

template
struct deduce_from_tag
{
typedef std::list type;
};

template
struct deduce_from_tag
{
typedef std::string type;
};

template
struct deduce_from_tag
{
typedef std::map type;
};

template
struct deduce_param1;

template
struct deduce_param1
{
typedef T type;
};

--------------------------------------------------------------------

by michael toksvig (not verified)

Eric Niebler submitted an implementation of a FOREACH macro to boost that was really clever. It has since been yanked. Here is the readme:

BOOST_FOREACH
by Eric Niebler

The BOOST_FOREACH macro is a simple, intuitive and typesafe way to iterate
over a collection. It is inspired by similar looping constructs in other
languages, particularly C#. It is intended for inexperienced programmers who
do not know much about iterators, predicates and half-open sequences. It is
also useful for anybody who wants to type fewer characters when writing loops
over sequences. Its salient features are:

- It works over STL containers, arrays and null-terminated strings.

- Your loop variable can be a value or a reference. If it is a reference, then
any changes you make to it get written through to the underlying sequence.

- It generates near-optimal code. That is, it is almost equivalent to the
hand-coded equivalent.

- It behaves just like a for loop. That is, you can break, continue, goto or
return out of the loop body.

The syntax is as follows:

std::list int_list;
...
BOOST_FOREACH( int &i, int_list )
{
i += 10;
}

Note that the loop variable, i, is a reference to the ints within int_list. You
can also declare your loop variable before the BOOST_FOREACH loop:

int i;
BOOST_FOREACH( i, int_list )
{
std::cout << i << std::endl;
if ( -1 == i )
break; // this breaks out of the BOOST_FOREACH loop
}

Acknowledgements

Many of the ideas for BOOST_FOREACH are described in the Nov 2003 C/C++ Users
Journal article by myself and Anson Tsao. That article describes how to
implement a FOR_EACH macro that works with .NET collections. BOOST_FOREACH is
a reimplementation of the original FOR_EACH macro that works with native type.
It also corrects a number of shortcomings of that implementation.

by Eric Niebler (not verified)

You can find the code to BOOST_FOREACH along with a PowerPoint presentation about it at http://www.nwcpp.org/Meetings/2004/01.html.

Enjoy!
Eric Niebler
Boost Consulting
www.boost-consulting.com

by Craig Buchek (not verified)

God, I love the Internet! You mention somebody's name in a thread, and he comes and replies to the thread with complete details. Thanks Eric.

by David Johnson (not verified)

"Driven by consumer electronic devices such as mobile phones and PDAs, desktop applications are moving away from standard widgets and styles towards more customized user interfaces"

While I'm glad Qt 4 will have a better style engine, and that it will better support miniscule low-bit displays on phones and devices, isn't this another word for "skins"? And aren't the current Qt style preferable to bitmapped skins? I don't want my KDE desktop looking like an LCD display. Nor do I want it looking like something Nullsoft drew.

by uga (not verified)

> And aren't the current Qt style preferable to bitmapped skins?

I'm not sure if the article actually meant that. Anyway even right now you can use bitmaps to render styles, and that's what actually some styles do right now. Discover which of those ;)

> I don't want my KDE desktop looking like an LCD display

heh, discover which of the current styles use images ;)) Does any look an LCD? :))

I know what you mean, but I don't think you should worry, new Qt's drawing methods and styles will just improve. I wouldn't worry that much :))

by wilbert (not verified)

this looks very cool!

by Pilaf (not verified)

Couldn't agree more.

by Rice (not verified)

That shiznit is off the hook!

by KDE User (not verified)

OK. I love the look of the Qt iterators. One big thing I dislike about C++ is the STL. It is soooo ugly. C++ is an inherently ugly language, but at least Trolltech are doing their best to make it useable. Just compare:

foreach (QString s, list)
sum += s.length();

to

QList::const_iterator i;
for (i = list.begin(); i != list.end(); ++i)
sum += (*i).size();

!!! Neither is as nice, IMO, as:

list.each {|s| sum += s.length }

of Ruby, but the Qt way makes things much more bearable in C++.

by David Johnson (not verified)

Once you remove the template (and casting) syntax, C++ isn't ugly. Quite the opposite. It makes a readble and easy-to-write language. But only if you stay away from that awful template (and casting) syntax.

by KDE User (not verified)

I must disagree. I find C++ to be ugly. It's a bolt-on to C, with a bunch of other bolt-on features. It's too hacky for my tastes. For example, why not make a sane syntax for abstract classes, such as
abstract class Foo;

Instead, you can choose to set a method equal to zero (hello, what? does this make any sense at all?) or make the constructor private (makes more sense, but still not as clear, to me, as an "abstract" keyword).

I'm not saying that C++ is the world's crappiest language, but it's far, far, far from elegant. ESPECALLY, as you point out, when you add templates.

Languages, such as Ruby, that were designed from day one with OO in mind are much cleaner to work with. Now all we need is a Ruby compiler.. :(

by Marco Bubke (not verified)

But there are more pattern than OO. I like python more, but I believe its a question of taste.

IMHO language should be designed to be easily readalbe. Reading is IMHO much more important than writing.

by Ruediger Knoerig (not verified)

The template mechanism is one of THE reasons why C++ is THE language especially for high-complex numeric problems since it provide the capability to write complex but very performant programs. There is no substitution for this in any other language. Beside this, I won't miss any of the other features C++ provides. See the Java-guys: they try to integrate all these C++ features the'd called "depreached" like enums and other. IMHO Java has more structural disadvantages as C++. One of the biggest disadvantage is thatyou have to call new every time you want to instance an object.

by Simon Edwards (not verified)

Name one "high-complex numeric" program in KDE?

I agree with the other poster. Templates in C++ are an ugly preprocessor hack. It is a bit like operator overloading, the arguments for why operator overloading in C++ is so good always involve either complex numbers or matrix math...

--
Simon

by Wes Hardaker (not verified)

and yet for more language examples: Ah, perl...

map { $sum += $#$_ } @list;

Who couldn't understand that ;-)

by cm (not verified)

Perl - $Just @when->$you ${thought} s/yn/tax/ &couldn\'t %get $worse;

by Roberto Alsina (not verified)

Just to avoid language bigotry: this is a real Python line of code I wrote today (and no, I can´t find a simpler way to do it, and yes, it does something useful):

return apply(ObjectInstances[method].__class__.__dict__[params[0
]],(ObjectInstances[method],)+params[1:])

Notice how it´s ugly in a completely different way than perl? ;-)

Of course when I saw what I had to write, I was shocked. While a perl programmer seing this level of uglyness probably doesn´t even notice (just to bring back language bigotry ;-)

by Rich (not verified)

It's a shame that everyone pontificating about perl seems to know so little about it:

map { $sum += $#$_ } @list;

Try this instead, and show me how this is more obfuscated than any other language:

$sum += length for @list;

Oh of course - the $ to indicate a scalar, and @ to indicate an array - that's not how C/C++/python does it so it must be rubbish. Hey, is so much cooler than perl.

There are plenty of things wrong with perl, as there are with all other languages - use each for its strengths (and learn how to code idiomatically).

Rant over!

by stunji (not verified)

...and even Ruby isn't as elegant as the equivalent Perl:

$sum += length($_) foreach @list

but that's just me :)

by wow (not verified)

Nothing beats python :-)

sum=0
for string in li: sum=sum+len(string)

by Andy (not verified)

I'm 15 years old and one of these Delphi/Kylix/FreePascal guys :-)

sum:= 0;
for I:=1 to MyStringList.Count do
Sum:= Sum+Length(MyStringList[I]);

But now I'm also learning C#.

Andy

by El Pseudonymo (not verified)

But this is technically not the same as the other examples. It would be trivial to implement this in C++ via a macro. The reason why your example is different from the others is that it will only work with containers which have an subscript operator. It will not work with containers which can only be forward traversed.

by Kigr (not verified)

With Python, you can also do it in a more functional programming way:
reduce(lambda x,y:x+y,[len(s) for s in li])

The list comprehension '[len(s) for s in li]' returns the list of the lengths of the strings in li and the 'reduce' operator computes the sum:
[1,2,3,4] -> (((1+2)+3)+4)

by mark dufour (not verified)

ah, but the most Pythonic way would be:

sum([len(l) for l in list])

which is a) the nicest notation of everything I've seen here, and b) is the thing that pops right into your head when thinking about the problem.. right?

by wow (not verified)

Yeah, but only if you know sum() accepts lists :-)

by Rich (not verified)

Is:

sum([len(l) for l in list])

Really easier to read than the *idiomatic* perl equivalent:

$sum += length for @list;

There are a lot of muppets posting crap perl code on this site ATM - perhaps they should stick with a language they actually know.

BTW I've got no problem with Python, Ruby, Tcl, Perl, ... - folks should use whatever they're happy with!

by mark dufour (not verified)

>Is:
>sum([len(l) for l in list])
>Really easier to read than the *idiomatic* perl equivalent:
>$sum += length for @list;

not if you are already a perl programmer. yeah, I do not really like the way it reads. what are these extra characters, '$', '@' and ';'? I think I would prefer 'sum += length for list', that really is easier to read. you know that working memory is limited, and having all sorts of redundant characters on a line (especially one longer than this) makes it harder to read. then, the '+=' turns me off a bit. it just seems awkward, but also for beginners and for e.g. presenting code to a math professor it's not very readable. in Python you tend to 'transform' datastructures, so you don't need awkward constructions like this. I admit the Python expression isn't insanely obvious at first, but at least once you get it it reads easily, and it's not awkward at all. it just says what you want to do, almost literally: 'I want the sum of the lengths of the things in this list.' what does the perl version say? 'I want to += the length for this list, and it's not clear what $sum is, initially.' and how flexible is this perl construct? can I add for instance the numbers of two lists? in Python this would be [a+b for (a,b) in zip(l1,l2)]..

by Rich (not verified)

>what are these extra characters, '$', '@', ';'

But you have to know a little of any language before using it properly don't you:

$= scalar, @ = array, % = hash etc. Most of the other punctuation marks rarely have to be used or have English equivalents.

>but at least once you get it it reads easily, and it's not awkward at all

That's the whole point isn't it - once you get most (though not all :) languages they read easily! It's sad that much of the code posted by people to show how bad perl is often isn't idiomatic perl - it wouldn't take me long to write some hideous python, ruby, tcl, Java, C# etc code because I'd only have a relatively superficial knowledge of them.

> 'I want the sum of the lengths of the things in this list.' what does the perl version say?

You're being silly now - it says "sum the length of each item in this list". There's really not much difference here - they're both clearer than many other languages!

> it's not clear what $sum is, initially

Eh?

>in Python this would be [a+b for (a,b) in zip(l1,l2)]..

Yes, there's no doubt that's a nicer way than a perl equivalent - that's why zip is being introduced in p6. There's some great stuff in python, and p6 will certainly show some influence from python, but the fact remains I find it amazing that people are quick to judge other languages when they clearly have little knowledge of them.

I'm not implying you, rather the original posters of the perl examples.

by Rich (not verified)

Double posting - ah well never mind!

As I didnt provide code:

[a+b for (a,b) in zip(l1,l2)].

*Could* go to:

$sum = $a[$_] + $b[$_] for 0 .. $#a;

Not as nice - roll on p6!

by mark dufour (not verified)

I respectfully disagree with your statement, that most languages have the same readability, once you are used to using them. by readability I mean a lot of things, like: is a language orthogonal, so that different programmers can quickly understand each others code? is it compact yet still clear, so that you can see what is happening from a high level? does it do away with low-level details irrelevant to the essence of what you are doing? can you re-read your code again after having worked on something else for six months? is the code accessible to beginner (or new at the project) programmers, so they can easily add or change things? I think these, among other things of course, all contribute to the inherent 'readability' of a language. not to make this into a python-perl war, looking at it this way, I think it is safe to say that Java is more readable than C. I also think Python is more readable than Java, because you can do a lot more in much less lines, while still being perfectly clear as to what is happening. I think the addition of all sorts of more or less redundant characters in Perl (I forgot ';', '{' and '}' :-)) makes it a little less inherently readable.

but I admit I was probably overreacting a little.. Perl and Python are both great languages, and they are a lot more alike than that they differ..

by KDE User (not verified)

Code like that makes me glad I chose to migrate from Perl to Ruby, rather than to Python.

by mark dufour (not verified)

I don't know Ruby, but here is the corresponding code fragment someone gave earlier:

list.each {|s| sum += s.length }

can you tell me why you find this more readable than, say

sum([len(s) for s in list])

also, what is the value of sum initially? and, can you use this list.each.. construction as an expression itself?

by Richard Dale (not verified)

"also, what is the value of sum initially? and, can you use this list.each.. construction as an expression itself?"

You need to assign a 0 to sum. Array.each returns the array so you can nest calls - all ruby expressions return a value even 'if' statements

irb(main):008:0> list = ["a", "bb", "ccc"]
=> ["a", "bb", "ccc"]
irb(main):009:0> sum = 0
=> 0
irb(main):010:0> list.each {|s| sum += s.length }
=> ["a", "bb", "ccc"]
irb(main):011:0> puts "sum: #{sum}"
sum: 6
=> nil

Although doesn't look any more readable than the python to me - they both look just fine!

But ruby blocks and iterators are certainly very nice - I don't know if python works the same. Does it allow you to yield multiple values from a block? In ruby the little expression above is actually a sort of co-routine where the block and the Array yield control to each other for each iteration.

by mark dufour (not verified)

so printing out the sum takes three lines..? yes, Python also has multiple return values (I do not understand how a ruby block works?), a general iteration protocol, and yield statements that allow functions to temporarily return and later resume what they were doing.. I don't thnk there are big semantic differences between perl, ruby and python. it's mainly the syntax..

by Sad Eagle (not verified)

I think yield is a bit easier conceptually to understand if it's viewed as an invocation of a closure and not a co-routine transfer, since IIRC, the block can just return, and not transfer back, no? (Although the co-routine definition certainly matches the history of the yield keyword), particularly considering the roughly interchangeability with Proc/Lambda

by Richard Dale (not verified)

A block can either return or yield.

So here is the same thing in ruby 'functional style'. You use the collect method to map a function onto each element of the Array:

irb(main):018:0> list = ["a", "bb", "ccc"]
=> ["a", "bb", "ccc"]
irb(main):019:0> sum = 0
=> 0
irb(main):020:0> list.collect! {|s| sum += s.length }
=> [1, 3, 6]
irb(main):021:0> puts sum
6

All the other examples have been in this functional style. The iterator/yield approach is more powerful especially once you start to nest them.

by Sad Eagle (not verified)

It's compositional and perfectly orthogonal; it involves two concepts (blocks and methods) which are found in every single program all over the place. It's just passing a code fragment to the .each method of the list, to call on every element. It does not need a special syntax to construct a new list of values by iterating over an another list, which I am guessing the Python example is doing. Also, as a matter of my own personal preference, the Ruby example follows a hierarchical structure of control flow, where outer control statements are on the outside in the code (yes, I never uses the postfix forms of if or unless in Ruby code)