 Great, so I want to welcome everyone to October's Houston functional programming users group. And we today have with us John, Kevin or Johnson, who is one of my favorite speakers. He always has fun and interesting and smart presentations. And I was telling my wife, last night over dinner, I was like, Oh, yeah, John's gonna, you know, speak and she was trying to remember like, Oh, who is that? I was like, Oh, well, like the first time that I met, he started off by saying, Well, I'm going to do some sociology. I'm going to like, you know, mess it up and I really hope there aren't any sociologists in the audience. And so I laughed and but it turned out that his sociology was spot on. So, with that, I will turn things over to John. Welcome. Thank you so much. So, my name is John I actually did do a functional programming user talk about sociology, believe it or not. I have kind of a reputation I think for doing strange talks, or talks that kind of make you have to start somewhere other than functional programming. So, a little bit of background about me. I did study computer science in college. I was an English and history major. I had a whole career in some other kind of development before I discovered that I could make more money doing software development. And it was fun. And I've been doing that for a long time now. And the most fun I have is when I do F sharp. I'm just going to be honest. For the last couple of years, I did a project in F sharp. I really enjoyed that that came to an end. I changed employers. I went from improving to GCC like some of the other people here. And so now I'm doing mostly C sharp in real life. But I still love to dabble in F sharp. And this this presentation and this piece of software that I started really came about because I wrote a bunch of F sharp for this project I was on. And it was the ugliest F sharp I had ever seen. Now, that wasn't my fault as it usually is. Jared can tell you I usually write on the code. But this was ugly because of the situation. So let me explain a couple of things. The best open source PDF generation software in .NET uses sort of an old faculty with, you know, builder kind of approach. If you've done some C sharp, you probably see that the problem you run into there is that every other line in your F sharp code has to have it ignore. Because the C sharp builder things always return an object so you can keep, you know, dotting on to the end of it to do stuff. And that was a little frustrating. And just generally, there's a lot of dotnet applications that are designed for C sharp because most people who are in the dotnet world do C sharp. That's pretty reasonable. So I decided that it would have been a lot nicer. If I could have had a different interface into this application. And that's basically where it stood. And then on the project I was working on, it looked like we were going to have to create Excel files. Everybody know what Excel is? Yeah, yeah, okay. This is a test to see if people are awake because I know you know what Excel is, right? Okay, so I assume everybody knows what Excel is. I assume everybody knows what PDFs are. Yeah. How many people have ever had to generate an Excel file or a PDF file from code? Raise your hand. Yes. Yes. Yes. Okay. How much time was it? Exactly as much as you think it was. Exactly. It was, it was more fun the fifth time I did it. Yeah. Okay. So I was looking around for a library that might let me do, you know, create Excel files. There's a ton of those at dotnet, right? But they're all C sharp based. And I ran across this little project where a guy named Kit Eason had put together a wrapper around closed XML. Closed XML is a really nice dotnet library for creating Excel files. The name is kind of a play of open XML, anyway. Closed XML is okay, but it's, anyway, what he did was he put a list processing front end to it to make it look like Elb. Anybody done any Elb? Anybody familiar with Elbish? Yes. Okay. So it'd be really helpful to the extent that you're familiar with Elbish, which is a way of doing HTML, but like with lists. And so I thought that was really cool. Too bad nobody's ever done that for PDFs. And I thought, well, maybe I could do that. I thought before I saw this little FS Excel, which if you want to go look it up on GitHub, you can. Before I saw that, I thought that would be a really hard thing to do. And I looked at his code and it was easy enough that I even contributed some features to that. I thought, like, this is a great idea because most of these things that create Excel or PDF files, they're complicated. Would everybody agree with that? That they're complicated? Because PDF and Excel have lots of features and they, you know, there's just a lot of stuff. And most of the time, you don't really need to use all of the features. So that was what got me started down this path. Now, when we clear that this is not going to be the PDF library that you're going to use if you need to do really complicated PDF. Like, that's not what it's designed to do. My experience, the PDF files that I've generated programmatically fall into some fairly simple categories. So invoices, most businesses like to send out invoices because that's how they get their money, right? And so that's one thing that you do. The other thing is quotes, you know, that's the other end of the pipeline where it's like, hey, here's what we can do for you. And in my experience, there's two things that are pretty common. You have to pull some data from your database or whatever, you know, the customer name and address and that sort of thing. And what gets really interesting is when you have to have multiple pages and you're not sure where the page breaks are. So that's actually kind of hard of PDF. Does anybody know what PDF stands for? Portable document format. Very good. Some people get that wrong, but F is for format. So it is okay to say a PDF file. That's not redundant. Can't see anybody was worried about that. So the history of PDF, it's actually a subset of PostScript. Everybody familiar with PostScript? PostScript is a programming language to do what? Anything you want. It's a turn complete. It is turn complete. Also a lot of other things, but don't do anything you want with PostScript. It's designed. It's fun. But dots on a page to put black dots on a white page. You can do a whole lot more than that. So because they're really sort of focused on printers, like in their model, they tend to be focused on doing pages, which is fine if you have one page or if you know exactly where your page is going to break. But what I've discovered is frequently you end up with a situation where you have a variable number of paragraphs for your terms and conditions or whatever, right? And so what you need to be able to do is say, okay, put the stuff out there, you know, and you figure out where the page pagination goes. Has anybody ever written any code that tries to paginate stuff? I've actually had it. Yes. Yes. It's terrible. I mean, it's like, it is a legitimately hard problem. However, there is a library.net called Migradoc that was written like 20 years ago. Like it's seriously that old and it gives you a sort of word processor like feel to generating PDF. It actually generates all sorts of you can generate other stuff too, but most people use it with its associated PDF library called PDFSharp. The fact that there's libraries called PDFSharp really makes it hard to do an F sharp PDF, you know, like the Navy gets all messed up. Anyway, that's a whole nother issue. So I decided that this was going to be a cool thing to do. Now, how many people think it turned out to be too hard for me to do? Well, Jared, you're wrong. It wasn't too hard for me to do. Well, you might be right. I didn't answer yet. We don't know what you're going to say, Jared. But seriously, so in the model that I'm going to show you, there are no pages. That is, it doesn't create a page. What it does is you have some session level stuff you do. And then you have a document and then you have sections. And every section starts at the top of a page and you stuff things out of the section and you let the underlying library figure out where the paid breaks go. I will probably not expose it through my UI, but it will let you do windows and orphans and all sorts of other crazy stuff on your pages. But anyway, there's that. Now, does everybody kind of understand the problem I'm trying to solve? It's not everybody's problem. Probably not even most F sharp people problem, but it was my problem and I wanted a solution. So this is what I came up with. Now I'm going to show you a little bit of code. And then I want to sort of talk about the philosophy and the choices I made. And what I want to convince you of is using nothing more of functional programming than discriminating units lists and pattern matching. And an underlying library that's pretty powerful. You could do all sorts of really crazy stuff. And I actually like this as a programmer's interface. And what I mean by that is I like the whole idea that we call Elbish for reasons that I guess they came up with it first of just using a bunch of lists to tell the system what to do. Okay. Let me see if I can wake my. Yeah, there we go. My mouse seems to go to sleep quite a bit. So I'm going to try to share my screen. There we go. Can everybody see that? Perfect. Okay, so for some reason, Visual Studio Code just blew up on me today. So we're going to do this at LeapPad. Everybody's favorite tool, right? Okay, so I want to start off down here. So a list in F-sharp is inside of brackets. And if you put the items in the list on the same line, you put a semicolon to separate the list items. But generally what you'll see in a lot of lists is they'll break it out, you know, on different lines. That way you don't have the semicolons. People who write in F-sharp like to avoid as much needless use of punctuation as we can. Like the reason we don't do C-sharp is we ran out of semicolons. That's a joke. Now, so this list right here, right? This is actually a list for the document. There's some commands. Like I want to use this as, you know, the page sizes letter. So the default unit thing is kind of important, but it's really an underlying library issue. The underlying library was written by some people in Germany. And for some weird reason, they use like centimeters and millimeters to measure things. What's up with that? They're sane and not crazy like we are. Anyway, being an ugly American, I'm going to use an itch as my default unit. Everything, the way the underlying library works is everything you do that requires a measure, but you have to specify what unit you want to use. We're going to use itches everywhere. We're going to do letter.a4. So here's my section. I can write a bunch of stuff, right? And then I send this list to a function called ridder's PDF. And then I say, I'll send that to a file and I give it a file path. And it generates a PDF. And later on, I'll like change this and show you that it really does generate a PDF. So that's what I want people to see. Now, obviously a real document is going to be a little more complicated than this. You know, you want to set margins and, you know, general stuff like that. But let's sort of go up and see all the ugly code that goes into this. Okay, so can everybody see that okay? Is it big enough and everything? Okay. Usually it's big enough for everybody else if I can see it because I'm old and, you know, the eyes go. So that's a bunch of opens. If you're familiar with F sharp, they just, those are namespaces that we're going to use. So I define a bunch of discriminated unions. Is everybody generally familiar with the idea of discriminated unions? I mean, you can kind of figure this out. It's a thing that can be either this or that, right? So, you know, it can be inches or centimeters. The page size can be a four letter. Now, the underlying library supports a whole bunch of other page sizes that I'll throw in there at some point. I wanted to keep this fairly simple for now. And so, you know, I've got some stuff like margins. Oh, by the way, you'll notice that all the numbers I defined as doubles that actually makes life a lot easier in C sharp, or excuse me, an F sharp, and it fits with the underlying model of the library that I'm using. They actually prefer to get things in as doubles. You know, there's alignment. Like these are these are the kinds of things, right, that you worry about when you're formatting a document, right? You want to have, you want to be able to tell, you know, the system whether you want the text left, right, center, justify everybody. That's pretty straightforward, right? Then you can format things, right? And this is so one of the options for a lot for format is an alignment of alignment. If you've never done that sharp, that looks a little weird, but it's okay, trust me. And this just says that this is the name of the case in the discriminated unit. This is it's type, right? So the rest of these are doubles. I've got a text item that can either be a style or string. I'm actually going to change this. I've been through about 27 versions of this design because I keep iterating over it. Eventually I'll quit and release something and I'll let you guys know when I do that. You know, so there's section items and now this is this is actually the thing right here. Okay, so at the top level, there are items that are, you'll recognize the page size, the default unit, right? From what I showed you before. This is a little thing that allows me to basically let you decide what you want for your default unit. And then every number that you give me where it requires, you know, that is a measurement will be in that unit. This is from the library. This is not the F sharp unit. Just so everybody knows that. There's a little bug in the library. So we do this PDF. What does that do? Well, it does a little housekeeping. It creates the document from the underlying library. I use a mutable here. So this is all code that once it works, you don't really have to look at. So I'm okay with using ignore and mutables and all that stuff. I mean, that's the whole point of what I'm doing is to put all that code here so that I can use it without looking at it. Right? It's all about my aesthetic values. That's all this is about. Nothing fancy. So for all items, you just march through and you process them and you do a match. And so if it's a page size, right? Well, you match it with either letter or a for all the other ones that will put it eventually, right? And you see, we've, you know, this is how you set a value, which in C sharp, it would be an equals, but that's not how we roll an F sharp. So you're going to set the page format to letter or the page format to a for any questions so far. No, it looks very clean. And especially when you showed how it was used book. I think I get what you're saying. Like how it's used perfect anyway. Right. And so then you like, okay, it could be a default unit. Right. So that case, we're going to take that mutable and send it either to inches or centimeters, right? And then every time we need to do that, we'll come down here and do this, this little bit here. And so we don't have to have a lot of repetitive anything you just say, okay, yeah, take your default unit and set this value to that. So now we're going to go through the section and a section just has is a list of items, right? Of its own kind. Right. So, so this is kind of interesting the way that our library works, we need a mutable to represent the section because we're going to create a new one. Every time we process this in a regular document, you're probably going to have multiple sections. So then we walked through the items. Right. So I came up with the notion of what I call a spacer. There's about 27 different ways to actually accomplish this with the underlying library. And this is what I mean by I want to hide some of the complexity. You have to make some decisions, but the most common thing in the world is you're going to put like their logo at the top of the page. And then you're going to put the title of the document or, you know, the quote for whoever, you know, and you're going to have these things. But you don't, you know, they're going to show you what they already have. Right. This is what always happens. It's like, oh, we got this out of our word processor. We want you to do that, but drive it from the system. Everybody familiar with this scenario is like, oh, we created this in this little app that creates PDFs. Right. So they'll have, you know, and it'll be like two inches and then there's the next thing. Right. And so I wanted to have a way to say, okay, I need some space. Right. So I called it a spacer. You sit at a double and the most convenient way to create that with this underlying library is just to add a paragraph. So that paragraph actually has no space of its own because I didn't add any text or anything to it. But I say, oh, there's a paragraph there. And there's this much space after it. So I get that much space. And this is, if it's an image, basically you give it a path to an image. Now, I will say that I thought about doing this a couple of different ways, but I decided what worked best for me. And since I'm really, really truly writing this just for me, if it's useful for other people, that's cool. But I had a thing I wanted to do. But basically you just, you give it a path to an image that you have already gotten to the right size. I don't want to try to do the imagery sizing or that nonsense. Get that out of the way with a tool that doesn't write because you're going to use the same images over and over and over. So, like, get the right size and, you know, all that stuff in a decent tool to get that done, right? And then, you know, I have this text that has, so text actually takes a list of text items that can either be a string or a style. That's basically so you can embed a bold or something inside your text that makes sense to people. Now, there's a whole lot more to this in the real world and the real version that I have. But for this, I wanted to keep it simple enough so that I could explain each section. But basically what you'll see is it just be more of this kind of stuff where at each level, you're going to process a list of items, which might have items, a list of items inside them and you're going to process them and you do the same thing over and over, which, you know, it's interesting in the sense that you have to figure out how you want to do it. But now that I've shown everybody this and hopefully you understand it reasonably well. Well, let me stop here. Any questions? But by the looks of it, it looks like a little lisp interpreter, right? Like a small like eval loop. A little bit in it. Yeah, yeah. I mean, that's what I'm associating it with. I remember writing something similar like from Haskell. The matching and like the types and the... Don't tell me anything about Haskell. I promise people there would be no Haskell talk. It looks very similar. I don't like... I don't do math. I don't understand category theory. I'm not really clear on what a bone ad is. I'm not even sure how to pronounce it. But here's the thing. No, it's not that complicated. That's what they all say. But let me tell you, when I look at the world, I see lists of stuff. I see discriminated unions like everywhere. That's just like in records, which I don't use in this, but you know, I could have. But to me, the entire world is made up of those things and functions that do stuff to those things, which is why, you know, I kind of enjoy this way of looking at the world. I never... I'll be honest with you. I've been doing this for over 30 years. I still don't get object-oriented programming. It just doesn't make any sense to me. I can do it. I mean, they're paying me to do it at GCC. I do it all day long. But like, I don't know. It just... Yeah. You do know this is being recorded. Oh yeah, I know. We can fix it in post. No, no, I'm going to make sure that... No, like, I spent most of my career writing C-Shark. Well, I did some VB too. But in fact, I think the reason I liked VB was that it was less OO. You know, I also... I'm perfectly fine doing imperative kind of stuff. I think that, you know, whatever works. Anyway, but I do tend to see the world not as objects, but as stuff. Records, DUs. And I just, like, to me, pattern matching just fits with my brainwork. So that's that part of it. So when you say that you see the world not as objects, how literally are we supposed to take this? So, okay, so I write business apps, right? Yeah. Okay, so, I mean, like, an invoice is an invoice, okay? If the invoice ID of this piece of paper and the invoice ID of this piece of paper are the same, everything else about them better be the same or somebody's going to jail, right? Rructurally, equality is what the rest of the world calls equality. But seriously, if you look at, like, things in the business world, like, you know, very few of those things have, like, behavior. Like, my favorite one is, like, oh, we have this object and we're going to have a save method on it. Like, have you ever been in the office? Like, documents don't save themselves. Somebody picks the thing up and stuffs it in the file cabinet, right? It's something that you do to it. Like, everything is a function. So the whole thing about sociology was my argument that functional programming is just Max Weber's theory of bureaucracy. It's like, you have these, you know, think about the DMV or whatever your least favorite bureaucracy is, right? What you do is you go in there and you have a piece of paper and you hand it to somebody and they do stuff with it. They might hand it to somebody else. And at some point, there's maybe some sort of reaction like, oh, you're going to take that driver's test or something like that. But in general, the way I view the world is a lot like what you see right here. It's like, okay, the things I could do something to it. Well, let's take the classic because every business likes to get paid, right? So your message of payment, right? Credit card, cash check, whatever. They don't have anything in common other than they're a way for you to give me money, right? That's a discriminated union. Now, we can fake that in the old world. We can have an eye payment interface and like, that's cool. And I do that when I'm writing C-sharp, that sort of stuff. But I just kind of see the world that way. And so this sort of simple functional programming has always appealed to me. So I was hoping, I was just really hoping that you were making a report about your perceptual system, like that you don't actually see objects. I was holding out for that. I don't think that's actually the case. I just don't have to model those objects in my code very often. Like, what is the classic OO example? Like, it's the animal, the dog and the cat and all that stuff. It's like, have you ever written anything like that? I mean, some people do. I mean, if you're going to write a game, you're going to have lots of, you might have lots of objects to do stuff. Like, I totally get that, right? I mean, that makes perfect sense. But in the business world, I think kids today, I always have to say that, kids today, like they suffer from not ever having seen a bureaucracy before computers. Like, I'm old enough to have been where I had to go to the Social Security Administration. Well, they had computers, but most organizations didn't. And like, you would actually fill out forms in triplicate. Has anybody filled out a form in triplicate lately? I haven't, but used to do that all the time. I mean, that's perfectly normal all the time, right? And why did you do that? Because you might have three different people who needed to see that document and process it in some way. Right? Which is the interesting thing is they needed sort of to be the same. They might get different stuff done to them, but they started out the same. Anyway, that's enough of me going on about my inability to understand object-oriented programming. Let's get back to, go ahead. Maybe it's you, you pet your dog. You don't pet your, you know, file of order, class, family, you know, pet. See, I don't have a pet. I actually live with two cats right now. Because my daughter moved back to stay with me for a few months and she brought a cat. And so I'm getting used to the fact, you know, there actually are animals, but I kind of like cats because they're jerks. Like, they don't expect you to be nice. They might like it if you are, but they don't really expect it. There are some kinds of pets that really expect you to be nice to them. That's a little bit too much trouble for me. Like, the cats are okay that I ignore them. Anyway, that doesn't have anything to do with programming. I don't know. Well, the full taxonomy is like a class hierarchy. But you might deal with an individual rather than its class of thing. Yes, that's probably true. But so one of the things I find interesting about discriminated unions is that the organizing principle for a discriminated union is what you use it for. Right. It's like the only thing that has to connect them together is that you're going to use it for the same sort of thing. Right. You're going to deal with it that way, which I think actually models the business world a lot more than people would like to think. I've always, I've always amused when I'm reintroduced to a giant code base with that creates DTOs everywhere. By the way, Peter, I have a few things to say about Quick Start. Wait, look, I have no memory of last week. So I will not take the blame for anything. Peter's work at Quick Start is some of the best programming work I've ever seen in terms of just sheer usefulness. But into the tip to solve it and solve it and solvable is a hard problem. She's at the PowerShell script that starts like 80 things. Yes. Awesome. Yep. That's all my best work at PowerShell, which is why I need to learn some raw other stuff. PowerShell is very much a functional programming language. It may be the ugliest functional programming language in the world, but it is a functional program anyway. I've gotten totally off track. Here's what I want to talk about. Before you do, can I jump in just some clarification on the distinction between strings and styles? Oh, okay. Just sort of content-wise, what is sort of being modeled there? Okay, so I'm probably going to change the name of style, but anyway. Actually, I got from the underlying library and I'm gradually like taking away the things that were the weirdness of the underlying library sort of surfaced into my model. But the idea is that you can do some formatting, right? And so what I'd like to get to is a point where, let's say you have font information. I think I took the font business out here, but with a font, you have the name of the font, the size, the color, all those things you can describe with a font. If you have a font item that's at the document level, for example, that should be your default font for the entire document. If you have one at the section level, you're saying, okay, this section is going to use this font. If you have one at a paragraph level, it's for that paragraph, right? If you have it in the middle of some text, it's for just the stuff that's in between it. Does that make sense? And so you want to be at, if you go back down here, I'm going to break my code, but all the way down here. So you want to be able to say, hello world, and then have some font information, and then some more text, right? Just kind of like you would do markup in Markdown or something. I haven't quite figured out exactly how I want to do that. That's why it's not implemented here. But generally, you know, I want those things. Right now it says the style is a string because the underlying library lets you define all that stuff and give it a name. And you can use the name instead of all the stuff, which is kind of a nice feature. Like you can say, okay, so I'm going to have my normal font, but it's going to be white or black. And so I'm going to call that inverted as an example of something I actually did in one of the documents I created because they wanted to have like a strip of black background with white text on top of it, which by the way, they only did that because they weren't printing the documents. It's really interesting to me that PDF really started out as a way to describe how something should look on a printed page. And now in most of the PDFs we generate, nobody ever expects to print them. Like they're actually designed to be viewed on the screen. In a consistent way. Right. So it's effectively like printing. It is. It's like printing to the screen. Without paper. Without paper, that's right. Don't have to smoke trees. We have moved forward a whole generation without print, without paper. All right, I'll stop. Valid point though. I have a question here. So, so for example, like a list of text items, let's say string hello and like style, like if you give a font style and then like you put a bunch of strings like like right next to it. Will the style apply to the one on the right side or the one on the left side? It's going to be the one on the right side. Mostly because that's easier to implement. Yeah. The idea, the idea I'm going with is, like, you should be able to tell by looking at this part of the code, exactly what the style applies to. I've just, I've gone through, I think, three or four different versions of making that work and I haven't really decided on what looks best. It's actually, to me, that's one of the more interesting problems of doing this is how do I make it so that it's easy to apply specialized styling to a particular string. Everything is easy until you get to the part where you need to make that one word bold in the middle of the sentence. And then you have to make some decisions about how you want to show that. The rest of it's all pretty straightforward. It really is. Maybe like the string can have another attribute style, like, you know, classic HTML format. I thought about that and I might end up there, but like I said, this is still very much experimental and I'm playing around with how I want to make it look. At some point, I'm going to put this up on GitHub if I can figure out which one of my now five, yeah, five GitHub identities I want to associate it with. You know what's a really strange though. I have two different ones that are associated with blinds account, because I was there as a consultant three or four years ago. But anyway, on the topic of you haven't decided how you want to make this look. Have you thought about, since this is sharp. Have you considered making this a computation expression. Great question. Yes, I did. It is too complicated for me. No, seriously. Yes, I mean that's a that's like a sharp. That's an obvious question to ask, right? Make it flat. Why not make it a computation expression. And my answer to that is, I really like these lists. I really do like doing something as simple as a list, because I can explain to almost anybody how list works. It's a very natural concept. We make lists all the time. And, you know, yes, I can tell the computer nerds that yes, it's a single link list, but you know, I can tell my six year old granddaughter that it's a list. And she knows basically what I'm talking about. Right. They have listed kindergarten or first grade. Right. They know how that is. You know, they line up. Somebody in the front and there's somebody next, you know, I mean, it is actually a really straightforward concept. Now, there are some things that like, you can't really do this way that you really have to do. Like, you don't have to. But the guy who wrote the x86 processor, the similar code processor as a computation expression. Has anybody ever seen that? That's the weirdest thing in the world. You just, you just, like, do your listing of your assembly, like, or your machine, excuse me, a similar instructions for the x86. And there's a guy wrote an F sharp computation expression that will take those and execute. Think about that for a minute. That's right. So yeah, if I was going to do something like that, I'd probably do a computation expression. But in this case, the value here, it's interesting when you go to do this. If you think about how the underlying library like this works, the order that you do things in is really important. Like, if you add the text, before you do the other thing, the text goes higher on the page, right? I mean, it is really, it actually matters. And lists are perfect for that, right? I played around with using some, I thought it might be useful to use a record for something like a font setup. But even within that, it didn't work out very well because it gets a little ugly if you don't want to specify every single thing. So this actually, it's kind of nice because you can specify as many or as few of the things about a font as you want, and it will change just those things. And it actually, in this case, I mean, I use records for all sorts of things, but there was no place for records in this one. It didn't work out that way. So I thought that was kind of interesting in doing that. So like I said, I don't know, I mean, there may be an audience of one for this, but I'm going to build it anyway. I may never even get a chance to create PDF files in a sharp again, but I don't care because the best thing about this was I had so much fun doing this. Now, granted, you might think I have a strange idea of what's fun, but it is actually pretty rewarding. I would recommend if you want to see what the technique can do, go look at FS Excel on GitHub because it's really kind of a slick thing to be able to generate Excel files with just like, oh, go to this, go to this cell and write this data there. And it's really, that's what got me interested in doing this is just how slick that was and how easy it was to add features because the guy who did it originally, I did a couple of small features because I was interested in it. And then I realized I needed, you know, to work for what I intended it for, I needed to be able to take an existing spreadsheet and stick some data at the top of the worksheet. Don't ask me why I just needed to do that. So I just built that functionality into that app and it was easy. I was amazed just how straightforward it is to do something like this. So that's really pretty much all I wanted to talk about. I hope this made a little bit of sense and people can kind of get the idea. I don't anticipate that other people will think it's as much fun as I did, but, you know, I do think it's an idea that you can use in other places where you are. In other places where you want to wrap something, you know, you have some really complex underlying library that you want to use and you want to make it just a little simpler for make the easy stuff easy. Now, I don't, I don't have any intention of doing anything, you know, really complicated with this. But, you know, I can keep adding features to it if I want, because there's tons of features. I'm going to add footnotes, because the library does a great job with footnotes. Anybody ever tried to do footnotes on multiple pages of PDF? That's not easy. I'm just going to say that this underlying library will actually it'll take a bunch of text, paginate it for you and then put the right footnotes with the right page numbers and everything. Where you want them, which is, like I said, I, I've had to do a little bit of that in my life and it's just, it's, it just gets tedious. Outputting text in a reasonable way is much harder than most developers think. I mean, if you could just spew it out, you know, to the console or something. Yeah, that's easy, but make it look nice for what people expect from a real document. That gets, that gets tricky. Anyway, any questions? Yeah, so, I was going to remark. Anthony mentioned something about the ability to write custom computation expressions in F sharp. I've tried doing something like that. I was actually inspired by as JCJ said that the x86 interpreter written in F sharp. And what I realized is I would get halfway through writing a computation expression builder. And then realize it was just easier to write it as a list interpreter, like JCJ has written and I think actually underlying that x86 interpreter is a list interpreter. I don't think it, I think the computation expression builder is mostly syntactic sugar on top of a of a function that just accepts an instruction as as input and mutates a state object. Okay, if anybody notices any change in my behavior, it's not because my boss showed up. Well, so, so, so actually, like on that note, you can actually you. It's been a while since I've written a competition expression. So, can't you have your function, exactly the way that you've added on, like in your module. And then that's one of the methods on the objects. So then so you can talk all of that away. Like you can keep it a list processor. And then the API that you expose is just the do notation. Exactly. Yeah, I've seen lots of really useful things in computation expressions. It's like, I'm going to take the part that you saw that interprets the items, make that into a library that people can then use. And that hides all of that nasty and like, it's okay that it's there I just don't have to look at it. You know, another thing that I was thinking of looking at the way that you have the list, you know nested inside one another is, it kind of reminds me of. I think it's the giraffe view engine. Have you seen that. I've seen that it's been a little awesome delicate but I want you to talk about it doesn't look a little bit like that too. I wonder if there's anything, you know, there that you could borrow. They just have all sorts of like boxes, you know, just a little Russian nothing at all. Yeah, I would prefer not to get too deep into the testing, but I do like the way the way you can do things with F sharp in terms of it. It forces the indentation right the indentation matters. And for the way I'm doing the list, I think it works really well. I think it looked to me it looked visually like, okay, I am, I am constructing this document in the following order, and I can see the hierarchy of where of what's going to apply to what that way. It just it's one of those things where it's like it's really it's not complicated. It's fairly straightforward. I just like I just like the way that looks, I liked it ever since I first saw the sharp implementation of Elmish I was like, that's really nice just because it doesn't look so much like a program as it does look like a document of some sort. Now, it's not going to look like the document you're building because you don't see the image, you know, it's not in that way at all. It's sort of the, okay, this is these are the components of the document that you can tell the order and what they're going to do. And one of the things I don't show it here is you could write F sharp code in the middle of all that too. If you look at FS Excel, you'll see some of that where they do that. And that that makes it really handy for when you're going to have to pull, you know, the customer's name and address and everything out of that, or, you know, you're going to have to substitute certain sections of your terms and conditions with others and, you know, that sort of thing. And that has been a fairly common requirement that I've seen where companies that sell either complicated stuff or complicated services, right, depending on what you decided to buy from the list of terms and conditions varies quite a bit. Like, you know, it's like, if you're hiring our people to go set this up for you, then there's these, you know, there's some rules around what sort of insurance you have to carry, you know, that sort of thing. And being able to generate that document and let somebody else worry about how many pages it is and where it goes but still be able to do footnotes is super handy. I can't say enough about the quality of the underlying library as much as I hate the interface. I mean, it's just, especially in F sharp, it was just painful to work with. But I endured the pain because it did so much stuff that I didn't want to do that I required. So for the, for the previous thing I was doing, you know, I used its ability to do the pagination, being able to decide where you want your foot, your page numbering to start over. You ever thought about that? So sometimes people want the page numbering to be from the very first page to the end of the page. And other times people want the page numbering to go from the section, right, with the section, which I don't want to do that. I want to let somebody else do that. But my, the way I get joy out of programming is figuring out the things I want to do and the things I want to let somebody else do. And I'm perfectly okay with the people who like to do different things. That's what makes life, you know, interesting is like, there are software developers who like to do that stuff. Like they like to get into the nitty gritty and make it all work just that way. That's not my approach. There are some things that I get that way about programming, but not that many. Okay, so any other questions, comments. So could, could you go back to the actual code? Sure. And talk a little bit about how closely does your interface map on to the underlying libraries interface. Okay. So that's, that's like the question I struggle with in a way. So it's probably too close right now. It's closer than I want it to be. And what I mean by that is the easiest way to build this is just to take, you know, the, like the add paragraph, right, and just expose that. That's not how I wanted it to work. How I wanted it to work was I have a pretty strong vision of how I put PDF documents together. I guess I've done that enough to know how I'm going to go about it. And that is, I see it very much as a, I want to set up the document default. I want to set up the page defaults, the margins or whatever. I really like the idea of having reusable styles, which they allow you to do in a very word processing sort of way. You don't see that in the code I have here, but basically you can define a style, give it a name and then reuse it anywhere in the document. And I've gone back and forth about whether I should expose that as part of this. In general, I tried to abstract away the library's way of doing things when they are sort of what I think of as kind of the generic thing to do. That's not that, there's not much of that because I think they, I kind of like most of the way they did things. The biggest thing I wanted to abstract away are the decisions about the 27 different ways to accomplish the same thing. Because there really are a lot of a lot of different tasks. There's many different ways to approach the I want two inches of blank space here. Right. And so it's like, I don't want to have to think about that. I want to figure out whichever one works most consistently and can be applied in the, you know, in any level of the processing of the list and use that. Right. So a lot of what I was trying to do here is just like, okay. They expose this very word processor looking interface. Has anybody ever looked at like the word processing markup language that word uses? Like, you don't want to do that. I understand why they did, but like that's not at all what I want to do. I want to say, okay, look, if you want to apply formatting or if you want to apply styling to part of your text, it should be, it should work the same way. Whether you're doing it for the whole document or for just this word. Right. And that's really what I'm trying to go for there is to get it to basically a simplified version of what they offer. And I understand why libraries end up this way because everybody wants another feature. And these guys have had a long time to build this. Although they haven't really added very many features. It was a commercial product for about 10 years. And then they went open source and at some point it got hard to add features. And the thing that really broke everybody was not at core because this library and most other PDF libraries used a lot of windows drawing functions to get the graphics in. I don't show any graphics in here. I'm going to add the graphic pieces later. Mostly not in graphics so much as tables because most of the documents I ended up doing the tables. But anyway, so people have struggled to replace all that functionality in a way that's cross-platform. But this particular version of the library that I'm using has done that by incorporating the six labor image sharp stuff. That's this particular namespace in the LL but they have a ton of stuff for image processing. And so it's taken a while for the library to work effectively in .NET Core. There's also a bunch of things that you would think are minor but actually you have to figure out how you're going to deal with them. The default place to look for your fonts is different on Linux or Mac or Windows. So you don't see it here because I haven't gotten to it yet. But there's this whole bit with a font resolver or letting people just hand you a directory where you're supposed to find the fonts. But that has to be the same for the entire session for weird technical reasons. Anyway, did that answer your question or did I just ramble forever? Both. No, thank you. That was helpful. The other question that I had is, do you happen to have a more complete document that we could take a look at? I'm just curious to see if it's more complicated. I do, but I can't share it. Okay. It was work I did for some of you guys. I had hoped to have time to create a really complex document of the kind I've done before. And I'll be honest with you, I just ran out of time. So are there any other questions or is it time to move to the unrecorded open mic? We're not supposed to talk about that part. I forgot. We'll fix it in post, right? Exactly. All right, so I'm going to thank John very much for this talk. It was very, very interesting. And I am going to stop the recording now. And thank you so much. This is great. I really appreciate it. I hope you all had half as much fun as I did.