<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dw="https://www.dreamwidth.org">
  <id>tag:dreamwidth.org,2022-12-03:4065555</id>
  <title>Snail#</title>
  <subtitle>Snail#</subtitle>
  <author>
    <name>Snail#</name>
  </author>
  <link rel="alternate" type="text/html" href="https://snailsharp.dreamwidth.org/"/>
  <link rel="self" type="text/xml" href="https://snailsharp.dreamwidth.org/data/atom"/>
  <updated>2023-07-30T00:55:11Z</updated>
  <dw:journal username="snailsharp" type="community"/>
  <entry>
    <id>tag:dreamwidth.org,2022-12-03:4065555:4013</id>
    <author>
      <name>isaacschemm</name>
    </author>
    <dw:poster user="isaacschemm"/>
    <link rel="alternate" type="text/html" href="https://snailsharp.dreamwidth.org/4013.html"/>
    <link rel="self" type="text/xml" href="https://snailsharp.dreamwidth.org/data/atom/?itemid=4013"/>
    <title>Nice Little Things in Visual Basic .NET</title>
    <published>2023-07-30T00:54:19Z</published>
    <updated>2023-07-30T00:55:11Z</updated>
    <category term="dotnet"/>
    <category term="windows"/>
    <category term="visualbasic"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Posted by: &lt;span lj:user='isaacschemm' style='white-space: nowrap;' class='ljuser'&gt;&lt;a href='https://isaacschemm.dreamwidth.org/profile'&gt;&lt;img src='https://www.dreamwidth.org/img/silk/identity/user.png' alt='[personal profile] ' width='17' height='17' style='vertical-align: text-bottom; border: 0; padding-right: 1px;' /&gt;&lt;/a&gt;&lt;a href='https://isaacschemm.dreamwidth.org/'&gt;&lt;b&gt;isaacschemm&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;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.&lt;/p&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://snailsharp.dreamwidth.org/4013.html#cutid1"&gt;Read more...&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=snailsharp&amp;ditemid=4013" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2022-12-03:4065555:3568</id>
    <author>
      <name>isaacschemm</name>
    </author>
    <dw:poster user="isaacschemm"/>
    <link rel="alternate" type="text/html" href="https://snailsharp.dreamwidth.org/3568.html"/>
    <link rel="self" type="text/xml" href="https://snailsharp.dreamwidth.org/data/atom/?itemid=3568"/>
    <title>Breaking podcasts into chunks for burning to CD</title>
    <published>2023-04-20T17:57:23Z</published>
    <updated>2023-04-24T14:57:22Z</updated>
    <category term="cd"/>
    <category term="audio"/>
    <category term="visualbasic"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Posted by: &lt;span lj:user='isaacschemm' style='white-space: nowrap;' class='ljuser'&gt;&lt;a href='https://isaacschemm.dreamwidth.org/profile'&gt;&lt;img src='https://www.dreamwidth.org/img/silk/identity/user.png' alt='[personal profile] ' width='17' height='17' style='vertical-align: text-bottom; border: 0; padding-right: 1px;' /&gt;&lt;/a&gt;&lt;a href='https://isaacschemm.dreamwidth.org/'&gt;&lt;b&gt;isaacschemm&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;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 &lt;i&gt;forward &lt;/i&gt;when rewinding an MP3
at the slowest level.&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;Yesterday I put together a small Windows application to help with
this. It's called &lt;a moz-do-not-send="true" href="https://github.com/IsaacSchemm/CueSheetGenerator/releases"&gt;Cue
Sheet Generator&lt;/a&gt;, 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).&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;
&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://snailsharp.dreamwidth.org/3568.html#cutid1"&gt;Read more...&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=snailsharp&amp;ditemid=3568" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2022-12-03:4065555:2660</id>
    <author>
      <name>isaacschemm</name>
    </author>
    <dw:poster user="isaacschemm"/>
    <link rel="alternate" type="text/html" href="https://snailsharp.dreamwidth.org/2660.html"/>
    <link rel="self" type="text/xml" href="https://snailsharp.dreamwidth.org/data/atom/?itemid=2660"/>
    <title>Give me a yield break</title>
    <published>2023-03-15T18:23:15Z</published>
    <updated>2023-03-15T18:25:39Z</updated>
    <category term="visualbasic"/>
    <category term="csharp"/>
    <category term="dotnet"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Posted by: &lt;span lj:user='isaacschemm' style='white-space: nowrap;' class='ljuser'&gt;&lt;a href='https://isaacschemm.dreamwidth.org/profile'&gt;&lt;img src='https://www.dreamwidth.org/img/silk/identity/user.png' alt='[personal profile] ' width='17' height='17' style='vertical-align: text-bottom; border: 0; padding-right: 1px;' /&gt;&lt;/a&gt;&lt;a href='https://isaacschemm.dreamwidth.org/'&gt;&lt;b&gt;isaacschemm&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;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&amp;lt;T&amp;gt;. (In some cases, I'd argue that IReadOnlyList&amp;lt;T&amp;gt; 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&amp;nbsp;list, F# list, or array - but I digress).&lt;/p&gt; &lt;p&gt;Maybe the most obvious way to do this is by calling a function that explicitly returns an empty enumerable for you:&lt;/p&gt; &lt;pre&gt;
IEnumerable&amp;lt;string&amp;gt; SampleInterface.getAll() =&amp;gt; Enumerable.Empty&amp;lt;string&amp;gt;();&lt;/pre&gt;  &lt;p&gt;In F#, it would be even shorter, because of the aggressive type resolution:&lt;/p&gt; &lt;pre&gt;
interface SampleInterface with
    member _.getAll() = Seq.empty&lt;/pre&gt; &lt;p&gt;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):&lt;/p&gt; &lt;pre&gt;
IEnumerable&amp;lt;string&amp;gt; SampleInterface.getAll() {
    return Enumerable.Empty&amp;lt;string&amp;gt;();
}&lt;/pre&gt; &lt;p&gt;But there's also something clever you can do here, if you want to &lt;em&gt;think&lt;/em&gt; of your code in a different way - where instead of resulting in &amp;quot;an empty list&amp;quot;, it results in &amp;quot;no elements&amp;quot;. C# lets you build iterator functions, where your code defines an IEnumerable&amp;lt;T&amp;gt; (and runs every time the resulting object is enumerated). Any function with a &lt;code&gt;yield return&lt;/code&gt; or a &lt;code&gt;yield break&lt;/code&gt; is treated in this way by the compiler. This means you can implement a function that returns &amp;quot;no elements&amp;quot; just by doing this:&lt;/p&gt; &lt;pre&gt;
IEnumerable&amp;lt;string&amp;gt; SampleInterface.getAll() {
    yield break;
}&lt;/pre&gt; &lt;p&gt;It's a bit different in VB.NET, where iterator functions are denoted explicitly - so the yield break isn't needed:&lt;/p&gt; &lt;pre&gt;
Public Iterator Function getAll() As IEnumerable(Of String) Implements SampleInterface.getAll

End Function&lt;/pre&gt; &lt;p&gt;That is, in a very literal sense, a function that returns no elements!&lt;/p&gt; &lt;p&gt;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 &lt;code&gt;seq { }&lt;/code&gt; workflow without any elements in it, and suggests you use &lt;code&gt;Seq.empty&lt;/code&gt; or the empty list &lt;code&gt;[]&lt;/code&gt; instead.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=snailsharp&amp;ditemid=2660" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
</feed>
