At work I am developing an application using hand-coded Swing, and I've found that I have an easier time reading, writing, and maintaining hierarchical component creation using code blocks like:
JPanel mainPanel = new JPanel(new BorderLayout());
{
JLabel centerLabel = new JLabel();
centerLabel.setText("Hello World");
mainPanel.add(centerLabel, BorderLayout.CENTER);
}
{
JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0,0));
{
JLabel label1 = new JLabel();
label1.setText("Hello");
southPanel.add(label1);
}
{
JLabel label2 = new JLabel();
label2.setText("World");
southPanel.add(label2);
}
mainPanel.add(southPanel, BorderLayout.SOUTH);
}
So I wondered what that would look like using F# and WinForms, and I translated this code example (go to "Browse Code" tab, then click on F# -> editor.fsx in tree view) in two ways and I'd like feedback on which of the following two ways seems better. The first uses code blocks like the approach shown in Swing, and I think it is nice but a bit cluttered with begin ... end
everywhere:
open System
open System.Windows.Forms
let form = new Form()
form.Width <- 400
form.Height <- 300
form.Visible <- true
form.Text <- "Hello World Form"
begin
// Menu bar, menus
let mMain = new MainMenu()
begin
let mFile = new MenuItem("&File")
begin
let miQuit = new MenuItem("&Quit")
miQuit.Click.Add(fun _ -> form.Close())
mFile.MenuItems.Add(miQuit) |> ignore
end
mMain.MenuItems.Add(mFile) |> ignore
end
form.Menu <- mMain
end
begin
// RichTextView
let textB = new RichTextBox()
textB.Dock <- DockStyle.Fill
textB.Text <- "Hello World\n\nOK."
form.Controls.Add(textB)
end
The second approach is interesting because it takes advantage of the fact that in F# everything is an expression, but it seems a little harder for me to follow and I'm not sure if that's just because I'm used to the code block approach:
open System
open System.Windows.Forms
let form = new Form()
form.Width <- 400
form.Height <- 300
form.Visible <- true
form.Text <- "Hello World Form"
form.Menu <-
// Menu bar, menus
let mMain = new MainMenu()
mMain.MenuItems.Add(
let mFile = new MenuItem("&File")
mFile.MenuItems.Add(
let miQuit = new MenuItem("&Quit")
miQuit.Click.Add(fun _ -> form.Close())
miQuit
) |> ignore
mFile
) |> ignore
mMain
form.Controls.Add(
// RichTextView
let textB = new RichTextBox()
textB.Dock <- DockStyle.Fill
textB.Text <- "Hello World\n\nOK."
textB
)
Or maybe someone can suggest some other approach for structuring F# + WinForms code which is in this same spirit (i.e. emphasizing the component hierarchy both visually and in limiting scope).
Update
I recently learned that in F#, begin ... end
and ( ... )
are interchangeable. Which means that my concern with the first example is eliminated since I can write:
open System
open System.Windows.Forms
let form = new Form()
form.Width <- 400
form.Height <- 300
form.Visible <- true
form.Text <- "Hello World Form"
(
// Menu bar, menus
let mMain = new MainMenu()
(
let mFile = new MenuItem("&File")
(
let miQuit = new MenuItem("&Quit")
miQuit.Click.Add(fun _ -> form.Close())
mFile.MenuItems.Add(miQuit) |> ignore
)
mMain.MenuItems.Add(mFile) |> ignore
)
form.Menu <- mMain
)
(
// RichTextView
let textB = new RichTextBox()
textB.Dock <- DockStyle.Fill
textB.Text <- "Hello World\n\nOK."
form.Controls.Add(textB)
)
And indeed, the second example could be written as
open System
open System.Windows.Forms
let form = new Form()
form.Width <- 400
form.Height <- 300
form.Visible <- true
form.Text <- "Hello World Form"
form.Menu <-
// Menu bar, menus
let mMain = new MainMenu()
mMain.MenuItems.Add begin
let mFile = new MenuItem("&File")
mFile.MenuItems.Add begin
let miQuit = new MenuItem("&Quit")
miQuit.Click.Add(fun _ -> form.Close())
miQuit
end |> ignore
mFile
end |> ignore
mMain
form.Controls.Add begin
// RichTextView
let textB = new RichTextBox()
textB.Dock <- DockStyle.Fill
textB.Text <- "Hello World\n\nOK."
textB
end
So syntax isn't an issue anymore, but there still is a difference in style.