Man, I started PDF::Declarative two days ago, and nearly have something that can do the PDFs I want. Turns out text layout is hard - who knew? But building declarative wrappers for new domains is relatively easy, given good example code.
So I'm really quite happy about the declarative framework; it's making me a faster, better, more productive programmer, and that's all I really need it to do.
An interesting semantic domain at some point would be the generation of new semantic domains... Speeding up the process of speeding up the process should, um, speed up the process.
Wednesday, February 24, 2010
Wednesday, February 17, 2010
Dialogs, fields, and magic variables
So I've obviously been spending too much time with this, but I added magic variables to Class::Declarative today, and used them for text controls in Wx.
In the Wx::Declarative framework, that becomes this:
And it works, as of right now.
A magic variable is one for which a handler is registered with the context. When we read or write that variable in the context, our handler is called. That means that code can get or write field contents just by referring to the field as the variable it's tied to - and you tie a field to a variable just by naming it.
So the wxPerl dialogs.pl sample is this code:
#!/usr/bin/perl
#############################################################################
## Name: samples/dialog/dialog.pl
## Purpose: Dialog wxPerl sample
## Author: Mattia Barbon
## Modified by:
## Created: 12/11/2000
## RCS-ID: $Id: dialog.pl,v 1.4 2004/10/19 20:28:13 mbarbon Exp $
## Copyright: (c) 2000 Mattia Barbon
## Licence: This program is free software; you can redistribute it and/or
## modify it under the same terms as Perl itself
#############################################################################
use Wx;
package MyApp;
use strict;
use vars qw(@ISA);
@ISA=qw(Wx::App);
use Wx qw(wxDefaultSize wxDefaultPosition);
sub OnInit {
my( $this ) = @_;
my( $dialog ) = MyDialog->new( "wxPerl dialog sample",
wxDefaultPosition,
);
$this->SetTopWindow( $dialog );
$dialog->Show( 1 );
1;
}
package MyDialog;
use strict;
use vars qw(@ISA);
@ISA=qw(Wx::Dialog);
use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
use Wx qw(wxDefaultSize wxDefaultValidator);
sub new {
my( $class ) = shift;
my( $this ) = $class->SUPER::new( undef, -1, $_[0], $_[1], [250, 110] );
# $this->SetIcon( Wx::GetWxPerlIcon() );
my( $ct ) = $this->{CELSIUS} =
Wx::TextCtrl->new( $this, -1, '0', [20, 20], [100, -1] );
my( $cb ) = Wx::Button->new( $this, -1, 'Celsius', [130, 20] );
my( $ft ) = $this->{FAHRENHEIT} =
Wx::TextCtrl->new( $this, -1, '32', [20, 50], [100, -1] );
my( $fb ) = Wx::Button->new( $this, -1, 'Fahrenheit', [130, 50] );
EVT_BUTTON( $this, $cb, \&CelsiusToFahrenheit );
EVT_BUTTON( $this, $fb, \&FahrenheitToCelsius );
EVT_CLOSE( $this, \&OnClose );
$this;
}
sub CelsiusToFahrenheit {
my( $this, $event ) = @_;
$this->{FAHRENHEIT}->SetValue( ( $this->{CELSIUS}->GetValue() /
100.0 ) * 180 + 32 );
}
sub FahrenheitToCelsius {
my( $this, $event ) = @_;
$this->{CELSIUS}->SetValue( ( ( $this->{FAHRENHEIT}->GetValue()-32 ) /
180.0 ) * 100 );
}
sub OnClose {
my( $this, $event ) = @_;
$this->Destroy();
}
package main;
my( $app ) = MyApp->new();
$app->MainLoop();
# Local variables: #
# mode: cperl #
# End: #
In the Wx::Declarative framework, that becomes this:
use Class::Declarative qw(Wx::Declarative);
dialog (xsize=250, ysize=110) "Wx::Declarative dialog sample"
field celsius (size=100, x=20, y=20) "0"
button celsius (x=130, y=20) "Celsius" { $^fahrenheit = ($^celsius / 100.0) * 180 + 32; }
field fahrenheit (size=100, x=20, y=50) "32"
button fahrenheit (x=130, y=50) "Fahrenheit" { $^celsius = (($^fahrenheit - 32) / 180.0) * 100; }
And it works, as of right now.
Tuesday, February 16, 2010
Wx::Declarative back where I was
Well, I've successfully factored the Class::Declarative out of Wx::DefinedUI (which is dead, long may it live) and I'm back to having all the stuff work that I had working last week. (!)
Going forward should be way easier now, and the hard stuff is factored out and unit tested so I can't break it as easily, but I feel oddly as though nothing had happened for a week. Except, of course, Class::Declarative is on CPAN now, which is very cool indeed.
So this is what works: code/closures, events (those are the core semantics), buttons, menus, message boxes (hardcoded text only), frames, sizers, dialogs. Next up is the status bar. Then I set out into serious wilderness by subclassing a window for the frame's client. Yikes!
Sunday, February 14, 2010
Some thoughts circling back to semantic programming now
OK. So this declarative style of programming can be seen as the systematic laying out of the semantic structure of the program at the same time we are building the code. I'm a little worried that this structure is still very thin (that is, the extremely complex ramifications of meaning that come along with human understanding of a program are missing in this structure), but it's still a beginning.
Let's consider this: we could see the Class::Declarative structure as a sort of prototype. But knowing sufficient amounts of semantics for any given class, we could take a working structure and "compile" it into a pure-Perl structure that doesn't depend on Class::Declarative at all. In fact, we could compile it into any language for which we knew how to express the semantics of the structure.
This is important. This is what we will end up doing much, much farther down the road.
As a more proximate goal, this is what I was fumbling towards in January. I read January's posts and they seem sort of naive. I think that bodes well.
Let's posit a set of semantics that talks about databases, PHP code, Web pages, and AJAX. That's what sproggler is talking about. This declarative-plus-semantic framework would be the backbone of that system, and it could express itself using templates of some kind.
These templates are symbolic units. Remember symbolic units? They connect semantic units (the nodes in a Class::Declarative structure) with syntactic units (the pieces of code we compile), and they are mediated by templates of varying degrees of abstraction. So at some point in the very near future, we're going to want to think hard about them.
Labels:
expression,
semantic programming,
sproggler,
symbolic unit
Parse::Indented on CPAN
Bit by bit, I'm establishing a useful toolset here.
I've been spending too much time today in organizing the unit tests for Class::Declarative. Test-driving programming has a higher initial threshold, but once you get the framework all set up, it really starts to take shape.
Anyway, Class::Declarative is parsing properly now; you'd think this would already work, but I spent some time generalizing the semantic framework to make it easy to build new semantic domains. I think this is really going to pay off in the medium term.
Saturday, February 13, 2010
Class::Declarative
I'm splitting the declarative-programming part out of Wx::DefinedUI. There are just so many areas I can think of where the declarative paradigm will be so useful!
Data declaration (tables and so forth). Testing! Other messaging frameworks like POE or Moose. And, yeah, semantic programming.
I've literally been thinking about this in one form or another for over twenty years. This is the first time I can see an actual way to get it implemented, dammit, so I can use it.
Anyway, refactoring the code is cleaning it up a lot. I always get the feeling if I just refactored enough everything would be a one-liner.
Closures in Perl
So I've been getting deeper into Perl lately. I wrote a little IRC bot class (Bot::NotSoBasicBot) and during the course of that, found myself writing an event queue that took anonymous subroutines to be run at a scheduled time. Only after doing that did I realize that anonymous subroutines in Perl are closures.
That was something of an epiphany. I took a Scheme class from Dybvig, sure. So I had been exposed to the concept of closures. But not until now did I really comprehend them or really realize what they're for.
Now I'm realizing that Perl is a much, much more powerful language than I ever gave it credit for. As I get deeper into Wx::DefinedUI, I'm pushing my own envelope, building code generators and all kinds of things. I feel as though this programming hiatus of the past few years really allowed me to approach the topic with a fresh eye.
Wednesday, February 10, 2010
Wx::DefinedUI
For quite some time (like, years) I've toyed with the possibility of defining GUIs under wxWidgets (in Perl, Wx, or in Python, wxPython) by using a sort of pseudocode decorated with actual code to execute the meat of the program. This year, the Muse has accepted my application, and I've started on Wx::DefinedUI in Perl.
To do this, I first managed to get past the hump that's always stopped me in the past: syntax. Bear with me, this is important.
See, whenever I start brainstorming about a new way to reorganize programming, I first scratch out a bunch of data structures in pseudocode, then I realize it's hard to implement that stuff. Then I run aground. For I while I thought XML would help, but no, XML is also too hard to type. This is what killed MagnifiCat, it's what killed the semantic programming of last year (earlier posts on this blog), and it's what killed the Web programming framework I started over the holidays.
But early this year, I got back to Wx. And I looked at the structure of one of the demo programs, and it looks like this:
use Wx::DefinedUI qw(-filter);That's it. Granted, that code doesn't do anything, it just demonstrates the use of box sizers, but there are two points I want to make about it.
dialog (resize) "Wx::BoxSizer"
size (box, v):
size (box, h) [1, GROW]:
button (id=OK) [0, ALL, 10] "Close window"
button [0, 0] "Button 2"
button [0, TOP BOTTOM, 5] "Button 3"
space [10, 10, 0, GROW]
size (box, h) [1, GROW]:
button [1, ALL, 5] "Button 1"
space [1, 30, 1, 0, 0]
button [1, GROW ALL, 5] "Button 2"
size (static, v) [2, GROW] "Wx::StaticBoxSizer":
button [1, GROW ALL, 5] "Button 3"
button [1, GROW ALL, 5] "Button 4"
First, it provides a detailed, extremely readable, and yet still parseable, overview of the application. If we provided IDs for all those buttons and wrote code to be called on click, we'd have a real application, and one that we could understand with no further ado.
Second - and this is important - as of yesterday, it works. I decided to go ahead and tackle the parsing problem. I looked up Parse::RecDescent and found it good - but then I went ahead and polished up my old XML::xmlapi as a structure manipulation module I can work quickly with, and wrote Parse::RecDescent::Simple to allow parsing of each of those lines. That stuff's already on CPAN, because it's working and stable to the point I need right now.
For parsing of the indentation, I've written part of Parse::Indented. It's not on CPAN yet, because I still want to add a feature allowing embedding of Perl code into my tree. Maybe tomorrow.
The crucial point here is this: I have a parsing framework that lets me use pseudocode to define things, things that will then run. Next step: use that very parsing framework to get back to the Web application framework and semantic programming. It should be easy!
Here's another point, by the bye: publishing early and often keeps the momentum going. I've published five modules to CPAN in the last week. It's heady stuff.
Subscribe to:
Posts (Atom)