Welcome to my new series on things I don’t understand about Apple’s premier user interface framework. I’m calling it…
[#]SwiftUWhy
To be clear, these are things I don’t understand, not necessarily things that are “wrong.” They sure look wrong (or at least “suboptimal”) to me! But maybe there are good reasons, and I just don’t know them yet. SwiftUI experts and historians, please tell me!
The first entry is coming up…
=> More informations about this toot | More toots from siracusa@mastodon.social
Why in the world does this interface look like this:
.padding(.top, 1)
.padding(.leading, 2)
.padding(.bottom, 3)
.padding(.trailing, 4)
…or this:
.padding(EdgeInsets(top: 1, leading: 2, bottom: 3, trailing: 4))
…instead of the much more idiomatic:
.padding(top: 1, leading: 2, bottom: 3, trailing: 4)
Like, who in the world thought of this foo(.key, value) API interface in a language with named parameters?!
[#]SwiftUWhy
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa One reason is because this api doesn't take an Edge, it takes an Edge.Set, which is an option set. This lets you combine them to let you write stuff like .padding(.horizontal, 10)
or .padding(.allButTop, 5)
.
Is that a good enough reason for a less-than-idiomatic api? I leave that to someone else to answer
=> More informations about this toot | More toots from Soroush@mastodon.social
@Soroush It is not! You could support all that and also have a sane named-param call! Guess which one everyone would use…
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa It’s also strange that we can specify nil to apply “default” padding:
.padding(.top, nil)
… but EdgeInsets has no equivalent.
=> More informations about this toot | More toots from adam@iosdev.space
@adam @siracusa It’s magical incantations all the way down, until they’re not magical.
I miss code you can reason about.
=> More informations about this toot | More toots from agiletortoise@mastodon.social
@siracusa ok, possibly the best hashtag ever.
=> More informations about this toot | More toots from octothorpe@mastodon.online
@siracusa I’ve got bad news for you on the discoverability front.
=> More informations about this toot | More toots from Gte@mastodon.social
@Gte Speaking of discoverability, I spent a while today puzzling over the “documentation” for this method, trying to figure out what it does and where or why one might want to use it.
https://developer.apple.com/documentation/storekit/entitlementtaskstate/map(_:)-8ly3v
But I did “discover” it, I guess. (It was in some sample code from a WWDC session.)
(And, no, I never really did figure it out.)
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa I’ve a lot of appreciation for Swift and SwiftUI. The language has really grown on me. The corresponding UI framework I’ve found a little inscrutable. I’ve been chalking it up to me being old and maybe not picking up new tricks so quickly. But, to be honest, I’m not sure anyone can? It feels like a thing that’s passed down through experience rather than inspection. While better documentation would be terrific I’d love a better synthesized way of knowing what modifiers were possible.
=> More informations about this toot | More toots from Gte@mastodon.social
@Gte @siracusa Yeah, "what modifiers are possible” is a problem, because they (almost) all are, although they don't all make sense in context.
One of the first things I thought was, “having every single API be a function / modifier on View certainly can't scale for an entire UI framework…”
Anyway, SwiftUI has a big learning curve, but it’s worth it.
=> More informations about this toot | More toots from jasonhowlin@mastodon.social
@Gte @siracusa Traditional autocomplete doesn't work well with modifiers, but this is something Copilot is actually pretty good at. Things that are idiomatic but not discoverable.
=> More informations about this toot | More toots from stevex@mastodon.social
@siracusa I suppose someone wanted to support the following:
.padding(.vertical, 8)
.padding(.horizontal, 12)
at all cost? #SwiftUIWhy
=> More informations about this toot | More toots from chbeer@mastodon.social
@chbeer But…
.padding(vertical: 8)
.padding(horizontal: 12)
.padding(vertical: 8, horizontal: 12)
So…why?!
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa I know… very good question. I ask that myself often, too.
Also the .buttonStyle(…), .listStyle(…) implementation: even Xcode can‘t understand the complexity most of the time
=> More informations about this toot | More toots from chbeer@mastodon.social
@siracusa The current design makes it easy to reuse one (or multiple!) EdgeInsets instances. That may be nice for ensuring consistency within a single view?
=> More informations about this toot | More toots from DavidAnson@mastodon.social
@DavidAnson Sure, but you can have that and the more idiomatic version. Guess which one would get more use?
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa I don't like it either. I add this to my projects:
https://gist.github.com/mjmsmith/040ffb4a8536b61bf479ad5b0abeea6e
=> More informations about this toot | More toots from marksmith@mastodon.social
@marksmith @siracusa FWIW, that changes the semantics of nil
from “platform dependent padding” to “no padding” and if you were to animate from nil
to some value, you'd lose the view identity due to the conditional.
Not trying to tell you what to do with your code base, just calling this out for those unaware.
=> More informations about this toot | More toots from dlx@mastodon.social
@dlx @siracusa I could be misunderstanding, but doesn't it have the same behavior as the built-in padding modifier? (In the image, trailing is applied both ways with the same result.)
=> More informations about this toot | More toots from marksmith@mastodon.social
@marksmith @siracusa This only affects the case where you pass in nil, e.g. .padding(.bottom)
which is effectively .padding(.bottom, nil)
.
=> More informations about this toot | More toots from dlx@mastodon.social
@dlx @siracusa Oh yes, you're right. In my modifier, passing nil (implicitly or explicitly) leaves the value alone rather than resetting it to the default.
A bit hacky under the covers, but I could use .nan as the default value in the padding() View extension, and test for .isNaN instead of nil in EdgePaddingModifier. That would make the behaviors match.
=> More informations about this toot | More toots from marksmith@mastodon.social
@marksmith @siracusa yeah, if you think that's worth it.
=> More informations about this toot | More toots from dlx@mastodon.social
@dlx @marksmith @siracusa Should be easy enough to fix the animations by summing the values into a single EdgeInsets to remove the conditional too :)
=> More informations about this toot | More toots from digitalfx@mastodon.social
@dlx @marksmith @siracusa Ah, although that would then conflict with the .nan default 😕
=> More informations about this toot | More toots from digitalfx@mastodon.social
@digitalfx @dlx @siracusa It's enough to make you think Apple had reasons for doing it the way they did in the first place. :)
=> More informations about this toot | More toots from marksmith@mastodon.social
@marksmith It’s not! There’s no reason to bend over backwards to match the weird functionality of an existing API when adding new, more idiomatic versions. The weird versions still exist for the people who want them!
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa one thing is that in most cases composing padding like that helps convey intent. If I want padding around edges, but more on left/right
.padding(8)
.padding(.horizontal, 8)
reads better than
.padding(top: 8, leading: 16, bottom: 8, trailing: 16)
=> More informations about this toot | More toots from auramagi@hachyderm.io
@auramagi .padding(horizontal: 16, vertical: 8)
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa how many overloads for a simple padding do we need? ;)
=> More informations about this toot | More toots from auramagi@hachyderm.io
@auramagi At least one more!
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa @auramagi one more? Well I often use:
.padding([.top, .bottom], 5)
But only because I didn’t know about .vertical!
=> More informations about this toot | More toots from joethephish@mastodon.gamedev.place
@siracusa My guess would be because this forces you to declare padding for all edges (if it’s one modifier) or is going to mess up diagnostics and type checking and stuff if they let you pick and choose because that would require multiple modifier variants
=> More informations about this toot | More toots from harshil@mastodon.social
@siracusa Also fwiw I think the EdgeSet variant is pretty good cause it also lets you do things just horizontal and vertical padding
=> More informations about this toot | More toots from harshil@mastodon.social
@harshil Somehow .frame() (almost) manages it, all with a handful of variants with normal named parameters.
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa Yeah that’s a good point!
=> More informations about this toot | More toots from harshil@mastodon.social
@siracusa Because there are system-default values that can’t be expressed with named arguments. Ideally, most of your paddings should look something like this:
.padding()
.padding(.horizontal)
This will make your views more portable across targets. A hardcoded point value might make sense on one OS, but it won’t transfer between device classes.
=> More informations about this toot | More toots from gufo@mastodon.nu
@gufo They already support explicit point values. They just do so in a non-idiomatic way. No one is saying to remove the APIs that have implicit default values. But the ones that take explicit values should be better.
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa Definitely agree. Having an EdgeInsets version but no idiomatic shorthands… that’s just madness.
=> More informations about this toot | More toots from gufo@mastodon.nu
@siracusa I don't know Swift, but maybe the dynamic linker has trouble with old apps when a new OS supports additional named parameters.
Also the implementation is probably nicer if you can pattern match with completeness check against one parameter instead of nesting if thatParameter
.
=> More informations about this toot | More toots from postweber@mstdn.social
@siracusa you can do things like
.padding(.vertical, 20)
and especially
.padding(onlyVertical ? .veritcal : .all, 20)
=> More informations about this toot | More toots from Jann@techhub.social
@siracusa being able to pass EdgeInsets allows for easier theming IMO, rather than needing to create your own struct and “unwrap” its properties to named parameters… but there’s no reason they couldn’t support named params and EdgeInsets, of course.
=> More informations about this toot | More toots from Drarok@mastodon.social
@Drarok Yes, that’s what I’m saying. By all means, keep the existing methods. But also make the ones that everyone expects to exist as well.
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa Coming from AppKit and UIKit, that’s 1 of the reasons (and there is a huge bunch) why I hate #SwiftUWhy
=> More informations about this toot | More toots from martind@mastodon.online
@siracusa Honestly no idea. But wonder if it’s something like:
To me
.padding(.top, 2)
Reads as “add padding to top of 2”. You choose some edges and a value.
and
.padding(top: 2)
Reads as “Set all padding. Override the default value on the top edge to 2”. You set a value for each edge. You don’t really choose an edge. .topPadding(2) might be closer? Very different default value behaviour.
So might be really confusing to have both so similar. I can see some arguments for the first.
=> More informations about this toot | More toots from Matthew@iosdev.space
@Matthew …and yet .frame() is different, despite the same reasoning making the same amount of sense there. (Which is to say, IMO, not much.)
=> More informations about this toot | More toots from siracusa@mastodon.social
@siracusa feels like a lot of the knowledge encapsulated in this old WWDC video has been lost https://nonstrict.eu/wwdcindex/wwdc2010/138/
=> More informations about this toot | More toots from glotcha@mastodon.social
@siracusa I mean this is the same language that has let vs var and one means "const". The language is dumb. Objective-C forever.
=> More informations about this toot | More toots from apple4ever@mastodon.social
@siracusa #SwiftUWhy
badum-tiss
https://youtu.be/H_NG1yXT6QY
=> More informations about this toot | More toots from njr@mathstodon.xyz
@siracusa hahaha excellent pun
=> More informations about this toot | More toots from adamprocter@fosstodon.org
@siracusa John, this is perfect for your blog! 👍🏼
=> More informations about this toot | More toots from fahrni@curmudgeon.cafe This content has been proxied by September (3851b).Proxy Information
text/gemini