Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "TimeSpans"
uuid = "bb34ddd2-327f-4c4a-bfb0-c98fc494ece1"
authors = ["Beacon Biosignals, Inc."]
version = "1.1.0"
version = "1.2.0"

[deps]
ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd"
Expand Down
10 changes: 10 additions & 0 deletions src/TimeSpans.jl
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,16 @@ function invert_spans(spans, parent_span)
return gaps
end

"""
intersect(span_1, span_2)

Returns a timespan that consists of the intersection of two timespans.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether "intersect" is really the right verb here. Describing it as the intersection of the two spans makes sense, but it kind of suggests to me that other set terminology would be applicable, but I don't believe there are any such cases. For example, TimeSpans.jl uses overlaps(a, b) rather than !isdisjoint(a, b), and TimeSpans.contains(a, b) rather than issubset(b, a). I could imagine that given that the query for "is there a nonempty intersection" is overlaps, "what is the intersection" would be overlap. But if overlap returns a span, it's not immediately obvious whether overlaps then is plural or present tense. I have no answers, only quandaries.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it helps any, the original function was called innerspan

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is really the set-theoretic operation though, (other than the error-if-disjoint lol).

my gripe with intersect_spans is the other part, the _spans: the other _spans functions operate on iterables of spans rather than pairs; the pairwise overlaps, contains don't have _spans.

I think TimeSpans.intersect is fine, it has the same semantics as the base function and not exporting it makes the scope clear a la contains

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll also add that Base.contains tends to come along with other collection-y methods, but the namespacing makes it pretty clear that it's different

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very, very late to the party but IMO TimeSpans.contains should be renamed to contains_span. (Actually, in basically all code I've written where I've needed that function, I do using TimeSpans: contains as contains_span, haha.) Having only part of the API namespaced feels inconsistent, and having a package with a function that has the same name as a Base function is really confusing. I strongly prefer intersect_spans over TimeSpans.intersect.

"""
Comment thread
chetchavat marked this conversation as resolved.
function intersect(a, b)
overlaps(a, b) || throw(ArgumentError("provided spans must overlap"))
return TimeSpan(max(start(a), start(b)), min(stop(a), stop(b)))
end

#####
##### Package extensions (TODO: remove this section once we require Julia 1.9+)
#####
Expand Down
12 changes: 12 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,18 @@ end
@test test_vec == []
end

@testset "intersect" begin
test_span_1 = TimeSpan(10, 100)
test_span_2 = TimeSpan(20, 80)
test_span_3 = TimeSpan(80, 120)
non_intersecting_span = TimeSpan(101, 150)

@test TimeSpans.intersect(test_span_1, test_span_2) == test_span_2
@test TimeSpans.intersect(test_span_1, test_span_3) == TimeSpan(80, 100)

Comment thread
chetchavat marked this conversation as resolved.
@test_throws ArgumentError TimeSpans.intersect(test_span_1, non_intersecting_span)
end

@testset "extensions" begin
@testset "ArrowTypes" begin
using ArrowTypes
Expand Down
Loading