isaacschemm: A cartoon of myself as a snail (snail8)
[personal profile] isaacschemm

Being (loosely) based on the original Visual Basic, it's not surprising that Visual Basic .NET has features specifically targeted towards Windows Forms development. When I want to make a quick GUI app to run on my PC, I often find it easiest to build the main code in a C# or F# library, and to build a thin frontend layer in VB.NET, for two reasons: the incredibly aggressive (in a good way) auto-formatting that keeps me from being distracted by code style, and the nice set of quality-of-life helpers the language gives you for this exact use case.

Read more... )
isaacschemm: A cartoon of myself as a snail (snail8)
[personal profile] isaacschemm

Sometimes I want to listen to a podcast on a TV, and sometimes the easiest way to do that is by burning it to a CD (either a CD-ROM with MP3 files, or - if it fits - a normal audio CD). Not every CD player has the greatest seeking features, though. I've got one whose fast-forward is more of a normal-speed-forward, and another that actually goes forward when rewinding an MP3 at the slowest level.

I figured one way of working around these issues - which could come into play for podcast episodes that are, like, an hour long - would be to split the podcast into segments of five minutes each. You'd need to make a normal audio CD (which means a limit of 75 or 80 minutes or so), but you could have gapless playback, while also being able to use track selection to go forward and back in chunks.

Yesterday I put together a small Windows application to help with this. It's called Cue Sheet Generator, and it takes in one or more audio files and converts them to either a set of .wav files (to burn with Windows Media Player Legacy or another app with gapless burning support) or a .wav/.cue pair (which ImgBurn and other such apps can handle).

The main program logic is small enough to fit into this post. I wrote it in VB.NET (there's nothing here C# couldn't do, I'm just tired of looking at curly brackets), and I thought it might be helpful to annotate it.

Read more... )
isaacschemm: A cartoon of myself as a snail (snail8)
[personal profile] isaacschemm

Working in .NET, I've been in a situation where I need to implement a function in an interface that's supposed to return an IEnumerable<T>. (In some cases, I'd argue that IReadOnlyList<T> might make more sense - this way, the caller knows it's not going to be a lazily-evaluated sequence, and you can still return a .NET list, F# list, or array - but I digress).

Maybe the most obvious way to do this is by calling a function that explicitly returns an empty enumerable for you:

IEnumerable<string> SampleInterface.getAll() => Enumerable.Empty<string>();

In F#, it would be even shorter, because of the aggressive type resolution:

interface SampleInterface with
    member _.getAll() = Seq.empty

There are other clever ways to do the same thing, though, and it might just depend on what you think is the clearest or most readable - which might just mean keeping it consistent with the code around it. First, you can always expand out the function (because clearer isn't always shorter - I think it really does depend on the context of what's around it):

IEnumerable<string> SampleInterface.getAll() {
    return Enumerable.Empty<string>();
}

But there's also something clever you can do here, if you want to think of your code in a different way - where instead of resulting in "an empty list", it results in "no elements". C# lets you build iterator functions, where your code defines an IEnumerable<T> (and runs every time the resulting object is enumerated). Any function with a yield return or a yield break is treated in this way by the compiler. This means you can implement a function that returns "no elements" just by doing this:

IEnumerable<string> SampleInterface.getAll() {
    yield break;
}

It's a bit different in VB.NET, where iterator functions are denoted explicitly - so the yield break isn't needed:

Public Iterator Function getAll() As IEnumerable(Of String) Implements SampleInterface.getAll

End Function

That is, in a very literal sense, a function that returns no elements!

Funny thing is that there's no real equivalent to an empty iterator function in F# (not that you'd need it); the compiler won't allow a seq { } workflow without any elements in it, and suggests you use Seq.empty or the empty list [] instead.

Snail#

A programming blog where the gimmick is that I pretend to be a snail.

Syndicate

RSS Atom

Expand Cut Tags

No cut tags

Style Credit

Page generated Jul. 12th, 2025 05:43 am
Powered by Dreamwidth Studios