Syntax matters
Gerade habe ich doch ein Stück Code hochgeladen? mit dem man jeden beliebigen Methodenaufruf in eine Invocation umwandeln kann.
Nun, das hat mir nicht gereicht. Jetzt hab ich mich noch mal hingesetzt und mich an einer anderen Syntax versucht:
// anstatt id invocation = NMCatchInvocation(@"fnord", stringByAppendingString:@"42"); // jetzt id invocation = [NMRecordingInvocation invocation]; [invocation recordWithTarget:@"fnord"] stringByAppendingString:@"42"]; // oder id invocation = [NMRecordingInvocation invocationWithTarget:@"fnord"]; [invocation record] stringByAppendingString:@"42"];
Und ich finde das ist von der Syntax her deutlich eleganter als das Makro.
Allerdings:
- Es ist etwa der doppelte Aufwand dass zu implementieren
- Das Makro erzeugt viel schnelleren Code (viel weniger allokationen)
Was soll ich davon jetzt halten? Small is beautifull? Keep it simple stupid? Oder ist doch wichtiger dass der zweite Versuch eher dem Objc-Spirit entspricht?
Mir ist das auch nach einem Tag darüber nachdenken erheblich unklar.
Grundeinkommen
Spannend wars heute auf dem Kongress.
Vormittags der Workshop über Simulationsmodelle über die Auswirkungen der Einführung von Grundeinkommen auf ein Modell der österreichischen Volkswirtschaft (in dem sich zeigte dass Gewinnsteuerfinanziertes Grundeinkommen das verwendete Modell stärker destabilisierte als ein durch negative Einkommenssteur finanziertes.
Well, dafür das der verantwortliche für das Modell nur einen Tag lang simuliert hat...
Danach ging es noch ein bisschen mit zellulären automaten weiter um damit zu simulieren wie sich das Wissen um Grundeinkommen in der Bevölkerung ausbreiten konnte.
Beides nicht großartig, aber doch ein interessanter Einblick darin dass auch in der Simulation eben nur mit Wasser gekocht wird. Will sagen: Das hätte ich auch gekonnt.
Danach gabs dann einen Argumentationsworkshop gegen Stammtischparolen und Killerargumente - das war mal was praktisches und für mich (trotz einer was Argumente angeht eher mageren Ausbeute) damit das Highlight des Tages.
Schlussendich noch eine (gefühlt endlose) Podiumsdiskussion. Bei der ich wie auf Kohlen saß - mir ist nach wie vor noch nicht klar wieso ich das so extrem nervig fand. Naja.
Immerhin kam mir dabei noch eine interessante Idee: Viel beschworen ist ja die Angst vor der Arbeitsunwütigkeit der Bevölkerung wenn es ein Grundeinkommen gibt. Dass die dann nicht mehr Arbeiten würden und es sich nur noch gut gehen lassen werden.
Tja, das kann man doch einfach Testen. Alle Gemeinden < $GRENZWERT dürfen sich für eine Lotterie anmelden. Die Leute die in der Gemeinde leben die Gewinnt (und nur die die zu dem Zeitpunkt dort leben) kriegen dann von da ab bis an ihr Lebensende ein garantiertes und bedingungsloses Grundeinkommen.
Voila - schon weiß man bald viel mehr darüber wie sich Menschen mit Grundeinkommen verhalten. Und dann kann man bald die Angst dass die dann ja alle nicht mehr Arbeiten würden fundiert wiederlegen. (Ok, kann man IMO jetzt auch schon, aber es wäre halt doch etwas anderes)
Bonus wäre natürlich wenn man gleich mehrere solcher Versuche macht um verschiedene Rahmenbedingungen zu testen.
Billiger als ein Bankencrash wäre es allemal - und viel Produktiver.
NSInvocations zusammenbauen...
...ist deutlich schmerzhaft.
Man muss eine Menge Aufwand treiben um aus einem objc-call etwas zu machen dass man schön hin und her passen kann.
Zum Beispiel:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
id aString = @"fnord";
id signature = [aString methodSignatureForSelector:@selector(stringByAppendingString:)];
id invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:aString];
[invocation setSelector:@selector(stringByAppendingString:)];
id appender = @"23";
[invocation setArgument:&appender atIndex:2];
[invocation invoke];
id returnValue = nil;
[invocation getReturnValue:&returnValue];
NSLog(@"Got: %@", returnValue);
[pool drain];
return 0;
}
Das nervt sobald man es öfters als einmal machen muss.
Darum hab ich mir nach langem nachdenken mal etwas zusammengebaut das das erleichtert. Es ist nicht perfekt und ich hab auch eine Menge Ideen wie man es noch schöner machen kann, aber es funktioniert. :)
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
id invocation = NMCatchInvocation(@"fnord", stringByAppendingString:@"23");
[invocation invoke];
id returnValue = nil;
[invocation getReturnValue:&returnValue];
NSLog(@"Got: %@", returnValue);
[pool drain];
return 0;
}
Und das sieht schon bedeutend besser aus.
C-Code für C und C++ verwendbar machen
Ich hab mich schon immer gefragt woher man eigentlich diese Defines nimmt um C-Code deklarationen so zu schützen, dass sie auch in C++ Code gut reingeholt werden können.
Ja klar, man kann das selber machen, etwas präprozessor bla und los gehts. Aber, das gibts ja vielleicht schon.
Enter #import <sys/cdefs.h>.
Und das ist in in Apple-Code praktischerweise immer schon includiert und enthält praktische Kleinigkeiten wie:
- __BEGIN_DECLS - jetzt kommen C-Deklarationen
- __END_DECLS - fettich
- __dead2 - diese Funktion kehrt nicht zurück (über das 2 könnte ich mich total amüsieren)
- __pure2 - diese Funktion hat keine Seiteneffekte
- __unused
- __printflike(formatArg, firstVarArg)
- __scanflike(formatArg, firstVarArg)
- __COPYRIGHT(string) - erzeugt eine globale variable
- __PROJECT_VERSION(string) - erzeugt eine globale variable
- __deprecated
Dann gibts natürlich noch <AvailabilityMacros.h> das auch noch ein paar Kleinigkeiten enthält - neben dem ganzen Zeug um APIs zu versionieren sind da auch noch mal Attribute definiert:
- WEAK_IMPORT_ATTRIBUTE -- funktion ist vielleicht da
- DEPRECATED_ATTRIBUTE -- funktion soll nicht mehr verwendet werden
- UNAVAILABLE_ATTRIBUTE -- funktion ist nicht vorhanden (z.B. weil sie API ist die erst in einer späteren Version des Frameworks unterstützt wird)
Vor allem __BEGIN_DECLS, __END_DECLS und __deprecated werde ich mit Sicherheit sofort benutzen. Ob ich die anderen auch verwende, weiß ich noch nicht. Mal schaun. :)
Ich find User-Ideen großartig
Einfach mal kreativ mit der Techik umgehen. Mal probieren und testen und dann die Erfahrung austauschen.
( via)
Unglaublich über sowas einfach herzuziehen. Einfach die eingebaute Kamera als Spiegel verwenden. Zum Beispiel damit.
Das Gedicht zum Bankendomino
Wenn die Börsenkurse fallen, regt sich Kummer fast bei allen, aber manche blühen auf: Ihr Rezept heißt Leerverkauf. Keck verhökern diese Knaben Dinge, die sie gar nicht haben, treten selbst den Absturz los, den sie brauchen - echt famos! Leichter noch bei solchen Taten tun sie sich mit Derivaten: Wenn Papier den Wert frisiert, wird die Wirkung potenziert. Wenn in Folge Banken krachen, haben Sparer nichts zu lachen, und die Hypothek aufs Haus heißt, Bewohner müssen raus. Trifft's hingegen große Banken, kommt die ganze Welt ins Wanken - auch die Spekulantenbrut zittert jetzt um Hab und Gut! Soll man das System gefährden? Da muss eingeschritten werden: Der Gewinn, der bleibt privat, die Verluste kauft der Staat. Dazu braucht der Staat Kredite, und das bringt erneut Profite, hat man doch in jenem Land die Regierung in der Hand. Für die Zechen dieser Frechen hat der Kleine Mann zu blechen und - das ist das Feine ja - nicht nur in Amerika! Und wenn Kurse wieder steigen, fängt von vorne an der Reigen - ist halt Umverteilung pur, stets in eine Richtung nur. Aber sollten sich die Massen das mal nimmer bieten lassen, ist der Ausweg längst bedacht: Dann wird bisschen Krieg gemacht.
Regexe updated
Hab ich mir doch gedacht, nur matching von regexen auf ganzen Strings ist doch langweilig - also hab ich noch containsRegex: hinzugefügt um etwas mehr komfort zu haben.
Da dachte ich ja zuerst dass ein Regex wie dieser hier eigentlich nicht funktionieren dürfte: .*^a angewandt auf "aaa" - aber interessanterweise funktioniert das ohne Probleme. Muss ich wohl noch etwas an meinen Regex-Verständnis feilen.
Ah well.
Wie kriegt man eigentlich mit was sich im Linux Kernel so tut?
Schließlich gibt es dort nicht so ausgezeichnete release notes wie man sie von Eclipse, Gnome oder Ubuntu kennt.
Die Antwort ist überraschenderweise: Heise lesen. Und sogar optional auch auf englisch.
Cocoa hat ja Regex Support
Überraschend.
Das der so vollständig ist, hätte ich nicht erwartet. Aber in der Tat, ICU-Regexe in ihrer ganzen Pracht. Völlig ohne eine neue externe Dependency.
Laut der Dokumentation sollte das sogar in 10.4 schon funktionieren - mit dem einen Caveat, dass multiline Support dort wohl von Hand eingeschaltet werden muss (via (?m))
Sowas wird da möglich:
if ([@"aaa" matchesRegex:@"a{3}"])
NSLog(@"gotcha");
// other examples
[@"argh fnord argh" matchesRegex:@".*\\bfnord\\b.*"];
[@"aaa" matchesRegex:@"\\w{3}"];
Und das mit extrem wenig Aufwand:
@interface NSString (SimpleRegexMatching)
- (BOOL) matchesRegex:(NSString *)aRegex;
@end
@implementation NSString (SimpleRegexMatching)
- (BOOL) matchesRegex:(NSString *)aRegex;
{
id predicate = [NSPredicate predicateWithFormat:@"self matches %@", aRegex];
return [predicate evaluateWithObject:self];
}
@end
Ich bin beeindruckt.
Die gegenwärtige Finanzkrise ist...
... eigentlich einfach zu verstehen.
Zum weglegen. :)
Aus einem Variablen-Namen einen String machen
Braucht man manchmal für Bindings. Gleichzeitig will ich aber nicht überall die namen meiner Variablen als Strings hinterlegen - schon alleine damit ich beim Refactorn auch alle Namen erwische.
Also den Macro-Prozessor zur Rettung:
#define NSStringize(aVariableName) @#aVariableName
- #
- macht aus einer beliebigen expression einen String
- @
- und das @ davor macht aus einem constanten c-string einen ObjC-NSString.
Und das problem ist gelöst. :)
_HiStOrY_V2_
Mit ein bisschen Hilfe von meinen Freunden...
Heute hab ich mal wieder die aktuelle Version von Bazaar (1.7.1) ausprobiert. Soweit ganz schnuckelig. Sogar der SVN Checkout von Adium hat hervorragend geklappt.
Ich muss sagen, beeindruckend.
Nur mit dem Plugin bzrtools hatte ich Schwierigkeiten, denn die darin enthaltene shell (ein geiles feature) zu benutzen brachte bzr reproduzierbar zum Absturz. :-(
Stellt sich mit hilfe von #bazaar und nach einigen Detours über den Python Debugger (nice!) und dtruss (nice!) heraus dass es an der libreadline liegt.
Die hat sich nämlich geändert und erwartet inzwischen am Anfang eines History-Files als allererste Zeile diesen eintrag: _HiStOrY_V2_.
Na toll. Und ansonsten stürzt das Programm einfach ab. Also wer sich das ausgedacht hat, der gehört aber auch echt erschossen. Wenigstens die Fehlermeldung hätte vernünftig sein können. Grumpf.
Ausnahmen vs. Regeln in der Usability
Heute hatten wir wieder ein schönes Beispiel für Usability unter Windows. Zuerst das Setting. Eine Bekannte hatte auf einem USB-Stick Fotos mitgebracht und diese sollten auf einem Windows-Vista Notebook dann angeschaut werden.
Das ganze wäre dann fast daran gescheitert, dass auf dem USB-Stick ein Trojaner drauf war und sich Windows nach Entdeckung und Beseitigung des Virus (durch irgend ein Third-Party-Programm) standhaft geweigert hat den Stick im Explorer anzuzeigen. Je nachdem in welchem der USB-Stecker man den Stick einsteckte erkannte Windows nicht mal das überhaupt ein USB-Stick eingesteckt war. Aber ich lenke ab, denn das Problem konnte ich mit etwas Windows-Shell dann doch lösen.
Zum Thema: Nachdem der Ordner mit den Bildern im Explorer aufgemacht wurde, ging es nach einem Doppelklick auf das erste Bild los - der Bildbetrachter ging auf und die Slideshow ging los.
Und das ist das Thema: Unter Windows öffnet der Bildbetrachter Bilder anders als sonst Programme Dateien öffnen - implizit wird dort nämlich der ganze Ordner geöffnet, damit man leicht eine Slideshow mit den Bildern starten kann.
Und das hat doch immerhin so gut funktioniert, dass die Slideshows doch zusammen kamen.
Das bringt aber die Abstrakte Frage mit, was passiert wenn solche "Ausnahmen" immer mehr werden. Verstehen die Anwender dann trotzdem noch das allgemeine Prinzip was dahinter liegt? Sind sie in der Lage zu abstrahieren und das Verhalten an anderen Stellen vorherzusagen?
Ich sehe ein Problem darin, dass Computer für die meisten Menschen "magisch" sind - man lernt nur die magische Formel, die zu einem konkreten Ziel führt. Dass hinter den 30 Formeln die man mit der Zeit lernt ein Prinzip steht geht dann nur allzu oft verloren.
Zurück zum Beispiel: Am Mac ist es so, dass man, wenn man eine Datei öffnet, dann auch nur diese Datei aufgeht. Und das ist auch so wenn man ein Bild öffnet. Unter Windows ist das anders, denn man öffnet im Bildbetrachter (wehe wenn die Zuordnung verloren geht, weil man ein Bildbearbeitungsprogramm installiert hat) der von sich aus schon die nächsten Bilder kennt und es einem leicht macht eine Slideshow zu starten.
Was ist Besser? Im Beispiel waren relative Laien in der Lage eine Slideshow zu starten - das ist ein Plus. Hätten sie das auch auf einem Mac geschafft?
Wann ist es Besser so eine Ausnahme vom regulären Benutzungs-Konzept zu machen und wann nicht? Für mich ist die Grenze völlig unklar - nur dass es irgendwann den Punkt gibt, wo zu viele Ausnahmen selbst zum Problem werden.
Creating NSNumbers from arbitrary values...
... without needing to care which constructor to use this time to get it right.
Well, I was offended by this just long enough, so I sat down and wrote a macro that allows this:
// Use like this:
id dict = [NSDictionary dictionary];
NSNumber *ten = NMMakeNumber(10.0f);
[dict setObject:ten forKey:@"numberOfFingers"];
[dict setObject:NMMakeNumber(23) forKey:@"fnord"];
[dict setObject:NMMakeNumber(YES) forKey:@"wantFries"];
I'ts almost the way Autoboxing works in Java or C#.
This quite eases the pain of creating NSNumbers correctly for me, because it means I don't have to repeat the type of what I am working with quite as often.
Pretty DRY. :)
Here's the code to a NSNumber category and a makro that makes this happen.

rss
