11
\$\begingroup\$

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.

asked Apr 11, 2011 at 2:29
\$\endgroup\$
2
  • \$\begingroup\$ I'd argue it looks difficult to follow because of the way you're using F# - WinForms certainly isn't its choice arena, and while there may be coincidental conveniences, it is inherently less concise for this purpose than the variety of .NET languages available that had UI in mind but mostly providing a generally explanatory syntax, a little like English. \$\endgroup\$ Commented Apr 11, 2011 at 10:37
  • 1
    \$\begingroup\$ @Mr. Disappointment: I respectfully disagree. It may not be obvious how to do it at first, but declaring hierarchies of objects in F# benefits from nested declarations. C-like languages like C# allow it only through blocks, resulting in a verbose use of braces. \$\endgroup\$ Commented Jun 8, 2011 at 8:00

1 Answer 1

4
\$\begingroup\$

Here is my take on your code:

open System
open System.Windows.Forms
let form =
 new Form(
 Width = 400,
 Height = 300,
 Visible = true,
 Text = "Hello World Form")
// Menu bar, menus 
let mMain = 
 let miQuit = new MenuItem("&Quit")
 miQuit.Click.Add(fun _ -> form.Close())
 let mFile = new MenuItem("&File")
 mFile.MenuItems.Add(miQuit) |> ignore
 let mMain = new MainMenu()
 mMain.MenuItems.Add(mFile) |> ignore
 mMain
form.Menu <- mMain
// RichTextView 
let textB = new RichTextBox(Dock = DockStyle.Fill, Text = "Hello World\n\nOK.")
form.Controls.Add(textB)

I tried to improve by assigning properties directly in the constructor call. I also used nested let declarations to reflect the hierarchy. Finally, I used indentation instead of explicit begin/end or parens to delimit blocks.

Note also how I used mMain within the declaration of the top-level mMain. Others might have used tmp, I think using the same name makes the intent clear. It might be a bit confusing for new-comers, though.

answered Jun 8, 2011 at 7:57
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.